blob: 7040f254739920e0529fc678c14cd0e9e3da8c44 [file] [log] [blame]
Prathmesh Prabhu40daa012013-04-03 10:35:03 -07001// Copyright (c) 2013 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 "shill/connection_health_checker.h"
6
7#include <arpa/inet.h>
8#include <netinet/in.h>
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -07009#include <stdlib.h>
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070010#include <sys/socket.h>
11#include <sys/types.h>
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070012#include <time.h>
13
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070014#include <vector>
15
16#include <base/bind.h>
17
18#include "shill/async_connection.h"
19#include "shill/connection.h"
20#include "shill/dns_client.h"
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070021#include "shill/dns_client_factory.h"
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070022#include "shill/error.h"
23#include "shill/http_url.h"
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070024#include "shill/ip_address_store.h"
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070025#include "shill/logging.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070026#include "shill/net/ip_address.h"
27#include "shill/net/sockets.h"
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070028#include "shill/socket_info.h"
29#include "shill/socket_info_reader.h"
30
31using base::Bind;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070032using base::Unretained;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070033using std::string;
34using std::vector;
35
36namespace shill {
37
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070038namespace Logging {
39static auto kModuleLogScope = ScopeLogger::kConnection;
Paul Stewarta794cd62015-06-16 13:13:10 -070040static string ObjectID(Connection* c) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070041 return c->interface_name();
42}
43}
44
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070045// static
Paul Stewarta794cd62015-06-16 13:13:10 -070046const char* ConnectionHealthChecker::kDefaultRemoteIPPool[] = {
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070047 "74.125.224.47",
48 "74.125.224.79",
49 "74.125.224.111",
50 "74.125.224.143"
51};
52// static
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070053const int ConnectionHealthChecker::kDNSTimeoutMilliseconds = 5000;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070054// static
55const int ConnectionHealthChecker::kInvalidSocket = -1;
56// static
57const int ConnectionHealthChecker::kMaxFailedConnectionAttempts = 2;
58// static
59const int ConnectionHealthChecker::kMaxSentDataPollingAttempts = 2;
60// static
61const int ConnectionHealthChecker::kMinCongestedQueueAttempts = 2;
62// static
63const int ConnectionHealthChecker::kMinSuccessfulSendAttempts = 1;
64// static
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070065const int ConnectionHealthChecker::kNumDNSQueries = 5;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070066// static
67const int ConnectionHealthChecker::kTCPStateUpdateWaitMilliseconds = 5000;
68// static
Ben Chan7fab8972014-08-10 17:14:46 -070069const uint16_t ConnectionHealthChecker::kRemotePort = 80;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070070
71ConnectionHealthChecker::ConnectionHealthChecker(
72 ConnectionRefPtr connection,
Paul Stewarta794cd62015-06-16 13:13:10 -070073 EventDispatcher* dispatcher,
74 IPAddressStore* remote_ips,
75 const base::Callback<void(Result)>& result_callback)
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070076 : connection_(connection),
77 dispatcher_(dispatcher),
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070078 remote_ips_(remote_ips),
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070079 result_callback_(result_callback),
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070080 socket_(new Sockets()),
81 weak_ptr_factory_(this),
82 connection_complete_callback_(
83 Bind(&ConnectionHealthChecker::OnConnectionComplete,
84 weak_ptr_factory_.GetWeakPtr())),
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070085 tcp_connection_(new AsyncConnection(connection_->interface_name(),
86 dispatcher_,
87 socket_.get(),
88 connection_complete_callback_)),
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070089 report_result_(
90 Bind(&ConnectionHealthChecker::ReportResult,
91 weak_ptr_factory_.GetWeakPtr())),
92 sock_fd_(kInvalidSocket),
93 socket_info_reader_(new SocketInfoReader()),
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070094 dns_client_factory_(DNSClientFactory::GetInstance()),
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070095 dns_client_callback_(Bind(&ConnectionHealthChecker::GetDNSResult,
96 weak_ptr_factory_.GetWeakPtr())),
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070097 health_check_in_progress_(false),
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070098 num_connection_failures_(0),
99 num_congested_queue_detected_(0),
Prathmesh Prabhu81404c62013-05-08 17:04:28 -0700100 num_successful_sends_(0),
101 tcp_state_update_wait_milliseconds_(kTCPStateUpdateWaitMilliseconds) {
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700102 for (size_t i = 0; i < arraysize(kDefaultRemoteIPPool); ++i) {
Paul Stewarta794cd62015-06-16 13:13:10 -0700103 const char* ip_string = kDefaultRemoteIPPool[i];
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700104 IPAddress ip(IPAddress::kFamilyIPv4);
105 ip.SetAddressFromString(ip_string);
106 remote_ips_->AddUnique(ip);
107 }
108}
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700109
110ConnectionHealthChecker::~ConnectionHealthChecker() {
111 Stop();
112}
113
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700114bool ConnectionHealthChecker::health_check_in_progress() const {
Alex Vakulenko8a532292014-06-16 17:18:44 -0700115 return health_check_in_progress_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700116}
117
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700118void ConnectionHealthChecker::AddRemoteIP(IPAddress ip) {
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700119 remote_ips_->AddUnique(ip);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700120}
121
Paul Stewarta794cd62015-06-16 13:13:10 -0700122void ConnectionHealthChecker::AddRemoteURL(const string& url_string) {
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700123 GarbageCollectDNSClients();
124
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700125 HTTPURL url;
126 if (!url.ParseFromString(url_string)) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800127 SLOG(connection_.get(), 2) << __func__ << ": Malformed url: "
128 << url_string << ".";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700129 return;
130 }
131 if (url.port() != kRemotePort) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800132 SLOG(connection_.get(), 2) << __func__
133 << ": Remote connections only supported "
134 << " to port 80, requested " << url.port()
135 << ".";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700136 return;
137 }
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700138 for (int i = 0; i < kNumDNSQueries; ++i) {
139 Error error;
Paul Stewarta794cd62015-06-16 13:13:10 -0700140 DNSClient* dns_client =
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700141 dns_client_factory_->CreateDNSClient(IPAddress::kFamilyIPv4,
142 connection_->interface_name(),
143 connection_->dns_servers(),
144 kDNSTimeoutMilliseconds,
145 dispatcher_,
146 dns_client_callback_);
147 dns_clients_.push_back(dns_client);
148 if (!dns_clients_[i]->Start(url.host(), &error)) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800149 SLOG(connection_.get(), 2) << __func__ << ": Failed to start DNS client "
150 << "(query #" << i << "): "
151 << error.message();
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700152 }
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700153 }
154}
155
156void ConnectionHealthChecker::Start() {
157 if (health_check_in_progress_) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800158 SLOG(connection_.get(), 2) << __func__
159 << ": Health Check already in progress.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700160 return;
161 }
162 if (!connection_.get()) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800163 SLOG(connection_.get(), 2) << __func__ << ": Connection not ready yet.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700164 result_callback_.Run(kResultUnknown);
165 return;
166 }
167
168 health_check_in_progress_ = true;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700169 num_connection_failures_ = 0;
170 num_congested_queue_detected_ = 0;
171 num_successful_sends_ = 0;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700172
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700173 if (remote_ips_->Empty()) {
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700174 // Nothing to try.
175 Stop();
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800176 SLOG(connection_.get(), 2) << __func__ << ": Not enough IPs.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700177 result_callback_.Run(kResultUnknown);
178 return;
179 }
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700180
181 // Initiate the first attempt.
182 NextHealthCheckSample();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700183}
184
185void ConnectionHealthChecker::Stop() {
Ben Chancc225ef2014-09-30 13:26:51 -0700186 if (tcp_connection_.get() != nullptr)
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700187 tcp_connection_->Stop();
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700188 verify_sent_data_callback_.Cancel();
189 ClearSocketDescriptor();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700190 health_check_in_progress_ = false;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700191 num_connection_failures_ = 0;
192 num_congested_queue_detected_ = 0;
193 num_successful_sends_ = 0;
194 num_tx_queue_polling_attempts_ = 0;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700195}
196
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700197void ConnectionHealthChecker::SetConnection(ConnectionRefPtr connection) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800198 SLOG(connection_.get(), 3) << __func__;
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700199 connection_ = connection;
200 tcp_connection_.reset(new AsyncConnection(connection_->interface_name(),
201 dispatcher_,
202 socket_.get(),
203 connection_complete_callback_));
204 dns_clients_.clear();
205 bool restart = health_check_in_progress();
206 Stop();
207 if (restart)
208 Start();
209}
210
Paul Stewarta794cd62015-06-16 13:13:10 -0700211const char* ConnectionHealthChecker::ResultToString(
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -0700212 ConnectionHealthChecker::Result result) {
Alex Vakulenko8a532292014-06-16 17:18:44 -0700213 switch (result) {
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -0700214 case kResultUnknown:
215 return "Unknown";
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -0700216 case kResultConnectionFailure:
217 return "ConnectionFailure";
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -0700218 case kResultCongestedTxQueue:
219 return "CongestedTxQueue";
220 case kResultSuccess:
221 return "Success";
222 default:
223 return "Invalid";
224 }
225}
226
Paul Stewarta794cd62015-06-16 13:13:10 -0700227void ConnectionHealthChecker::GetDNSResult(const Error& error,
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700228 const IPAddress& ip) {
229 if (!error.IsSuccess()) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800230 SLOG(connection_.get(), 2) << __func__ << "DNSClient returned failure: "
231 << error.message();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700232 return;
233 }
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700234 remote_ips_->AddUnique(ip);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700235}
236
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700237void ConnectionHealthChecker::GarbageCollectDNSClients() {
238 ScopedVector<DNSClient> keep;
239 ScopedVector<DNSClient> discard;
240 for (size_t i = 0; i < dns_clients_.size(); ++i) {
241 if (dns_clients_[i]->IsActive())
242 keep.push_back(dns_clients_[i]);
243 else
244 discard.push_back(dns_clients_[i]);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700245 }
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700246 dns_clients_.weak_clear();
247 dns_clients_ = keep.Pass(); // Passes ownership of contents.
248 discard.clear();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700249}
250
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700251void ConnectionHealthChecker::NextHealthCheckSample() {
252 // Finish conditions:
253 if (num_connection_failures_ == kMaxFailedConnectionAttempts) {
254 health_check_result_ = kResultConnectionFailure;
255 dispatcher_->PostTask(report_result_);
256 return;
257 }
258 if (num_congested_queue_detected_ == kMinCongestedQueueAttempts) {
259 health_check_result_ = kResultCongestedTxQueue;
260 dispatcher_->PostTask(report_result_);
261 return;
262 }
263 if (num_successful_sends_ == kMinSuccessfulSendAttempts) {
264 health_check_result_ = kResultSuccess;
265 dispatcher_->PostTask(report_result_);
266 return;
267 }
268
269 // Pick a random IP from the set of IPs.
270 // This guards against
271 // (1) Repeated failed attempts for the same IP at start-up everytime.
272 // (2) All users attempting to connect to the same IP.
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700273 IPAddress ip = remote_ips_->GetRandomIP();
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800274 SLOG(connection_.get(), 3) << __func__ << ": Starting connection at "
275 << ip.ToString();
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700276 if (!tcp_connection_->Start(ip, kRemotePort)) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800277 SLOG(connection_.get(), 2) << __func__ << ": Connection attempt failed.";
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700278 ++num_connection_failures_;
279 NextHealthCheckSample();
280 }
281}
282
283void ConnectionHealthChecker::OnConnectionComplete(bool success, int sock_fd) {
284 if (!success) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800285 SLOG(connection_.get(), 2) << __func__
286 << ": AsyncConnection connection attempt failed "
287 << "with error: "
288 << tcp_connection_->error();
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700289 ++num_connection_failures_;
290 NextHealthCheckSample();
291 return;
292 }
293
294 SetSocketDescriptor(sock_fd);
295
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700296 SocketInfo sock_info;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700297 if (!GetSocketInfo(sock_fd_, &sock_info) ||
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700298 sock_info.connection_state() !=
299 SocketInfo::kConnectionStateEstablished) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800300 SLOG(connection_.get(), 2) << __func__
301 << ": Connection originally not in established "
302 "state.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700303 // Count this as a failed connection attempt.
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700304 ++num_connection_failures_;
305 ClearSocketDescriptor();
306 NextHealthCheckSample();
307 return;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700308 }
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700309
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700310 old_transmit_queue_value_ = sock_info.transmit_queue_value();
311 num_tx_queue_polling_attempts_ = 0;
312
313 // Send data on the connection and post a delayed task to check successful
314 // transfer.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700315 char buf;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700316 if (socket_->Send(sock_fd_, &buf, sizeof(buf), 0) == -1) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800317 SLOG(connection_.get(), 2) << __func__ << ": " << socket_->ErrorString();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700318 // Count this as a failed connection attempt.
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700319 ++num_connection_failures_;
320 ClearSocketDescriptor();
321 NextHealthCheckSample();
322 return;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700323 }
324
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700325 verify_sent_data_callback_.Reset(
326 Bind(&ConnectionHealthChecker::VerifySentData, Unretained(this)));
327 dispatcher_->PostDelayedTask(verify_sent_data_callback_.callback(),
Prathmesh Prabhu81404c62013-05-08 17:04:28 -0700328 tcp_state_update_wait_milliseconds_);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700329}
330
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700331void ConnectionHealthChecker::VerifySentData() {
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700332 SocketInfo sock_info;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700333 bool sock_info_found = GetSocketInfo(sock_fd_, &sock_info);
334 // Acceptable TCP connection states after sending the data:
335 // kConnectionStateEstablished: No change in connection state since the send.
336 // kConnectionStateCloseWait: The remote host recieved the sent data and
337 // requested connection close.
338 if (!sock_info_found ||
339 (sock_info.connection_state() !=
340 SocketInfo::kConnectionStateEstablished &&
341 sock_info.connection_state() !=
342 SocketInfo::kConnectionStateCloseWait)) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800343 SLOG(connection_.get(), 2)
344 << __func__ << ": Connection not in acceptable state after send.";
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700345 if (sock_info_found)
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800346 SLOG(connection_.get(), 3) << "Found socket info but in state: "
347 << sock_info.connection_state();
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700348 ++num_connection_failures_;
349 } else if (sock_info.transmit_queue_value() > old_transmit_queue_value_ &&
350 sock_info.timer_state() ==
351 SocketInfo::kTimerStateRetransmitTimerPending) {
352 if (num_tx_queue_polling_attempts_ < kMaxSentDataPollingAttempts) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800353 SLOG(connection_.get(), 2) << __func__
354 << ": Polling again.";
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700355 ++num_tx_queue_polling_attempts_;
356 verify_sent_data_callback_.Reset(
357 Bind(&ConnectionHealthChecker::VerifySentData, Unretained(this)));
358 dispatcher_->PostDelayedTask(verify_sent_data_callback_.callback(),
Prathmesh Prabhu81404c62013-05-08 17:04:28 -0700359 tcp_state_update_wait_milliseconds_);
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700360 return;
361 }
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800362 SLOG(connection_.get(), 2) << __func__ << ": Sampled congested Tx-Queue";
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700363 ++num_congested_queue_detected_;
364 } else {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800365 SLOG(connection_.get(), 2) << __func__ << ": Sampled successful send.";
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700366 ++num_successful_sends_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700367 }
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700368 ClearSocketDescriptor();
369 NextHealthCheckSample();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700370}
371
Alex Vakulenko8a532292014-06-16 17:18:44 -0700372// TODO(pprabhu): Scrub IP address logging.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700373bool ConnectionHealthChecker::GetSocketInfo(int sock_fd,
Paul Stewarta794cd62015-06-16 13:13:10 -0700374 SocketInfo* sock_info) {
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700375 struct sockaddr_storage addr;
376 socklen_t addrlen = sizeof(addr);
377 memset(&addr, 0, sizeof(addr));
378 if (socket_->GetSockName(sock_fd,
Paul Stewarta794cd62015-06-16 13:13:10 -0700379 reinterpret_cast<struct sockaddr*>(&addr),
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700380 &addrlen) != 0) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800381 SLOG(connection_.get(), 2) << __func__
382 << ": Failed to get address of created socket.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700383 return false;
384 }
385 if (addr.ss_family != AF_INET) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800386 SLOG(connection_.get(), 2) << __func__ << ": IPv6 socket address found.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700387 return false;
388 }
389
390 CHECK_EQ(sizeof(struct sockaddr_in), addrlen);
Paul Stewarta794cd62015-06-16 13:13:10 -0700391 struct sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(&addr);
Ben Chan7fab8972014-08-10 17:14:46 -0700392 uint16_t local_port = ntohs(addr_in->sin_port);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700393 char ipstr[INET_ADDRSTRLEN];
Paul Stewarta794cd62015-06-16 13:13:10 -0700394 const char* res = inet_ntop(AF_INET, &addr_in->sin_addr,
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700395 ipstr, sizeof(ipstr));
Ben Chancc225ef2014-09-30 13:26:51 -0700396 if (res == nullptr) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800397 SLOG(connection_.get(), 2) << __func__
398 << ": Could not convert IP address to string.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700399 return false;
400 }
401
402 IPAddress local_ip_address(IPAddress::kFamilyIPv4);
403 CHECK(local_ip_address.SetAddressFromString(ipstr));
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800404 SLOG(connection_.get(), 3) << "Local IP = " << local_ip_address.ToString()
405 << ":" << local_port;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700406
407 vector<SocketInfo> info_list;
408 if (!socket_info_reader_->LoadTcpSocketInfo(&info_list)) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800409 SLOG(connection_.get(), 2) << __func__
410 << ": Failed to load TCP socket info.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700411 return false;
412 }
413
414 for (vector<SocketInfo>::const_iterator info_list_it = info_list.begin();
415 info_list_it != info_list.end();
416 ++info_list_it) {
Paul Stewarta794cd62015-06-16 13:13:10 -0700417 const SocketInfo& cur_sock_info = *info_list_it;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700418
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800419 SLOG(connection_.get(), 4)
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700420 << "Testing against IP = "
421 << cur_sock_info.local_ip_address().ToString()
422 << ":" << cur_sock_info.local_port()
423 << " (addresses equal:"
424 << cur_sock_info.local_ip_address().Equals(local_ip_address)
425 << ", ports equal:" << (cur_sock_info.local_port() == local_port)
426 << ")";
427
428 if (cur_sock_info.local_ip_address().Equals(local_ip_address) &&
429 cur_sock_info.local_port() == local_port) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800430 SLOG(connection_.get(), 3) << __func__
431 << ": Found matching TCP socket info.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700432 *sock_info = cur_sock_info;
433 return true;
434 }
435 }
436
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800437 SLOG(connection_.get(), 2) << __func__ << ": No matching TCP socket info.";
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700438 return false;
439}
440
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700441void ConnectionHealthChecker::ReportResult() {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800442 SLOG(connection_.get(), 2) << __func__ << ": Result: "
443 << ResultToString(health_check_result_);
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700444 Stop();
445 result_callback_.Run(health_check_result_);
446}
447
448void ConnectionHealthChecker::SetSocketDescriptor(int sock_fd) {
449 if (sock_fd_ != kInvalidSocket) {
Alex Vakulenko0951ccb2014-12-10 12:52:31 -0800450 SLOG(connection_.get(), 4) << "Closing socket";
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700451 socket_->Close(sock_fd_);
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700452 }
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700453 sock_fd_ = sock_fd;
454}
455
456void ConnectionHealthChecker::ClearSocketDescriptor() {
457 SetSocketDescriptor(kInvalidSocket);
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700458}
459
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700460} // namespace shill