Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: chrome/browser/local_discovery/privet_traffic_detector.cc

Issue 1553333002: Move cloud print specific files out of local_discovery (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@moveprn
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium 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 "chrome/browser/local_discovery/privet_traffic_detector.h"
6
7 #include <stddef.h>
8
9 #include "base/location.h"
10 #include "base/macros.h"
11 #include "base/metrics/histogram.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/sys_byteorder.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/network_interfaces.h"
16 #include "net/dns/dns_protocol.h"
17 #include "net/dns/dns_response.h"
18 #include "net/dns/mdns_client.h"
19 #include "net/log/net_log.h"
20 #include "net/udp/datagram_server_socket.h"
21 #include "net/udp/udp_server_socket.h"
22
23 namespace {
24
25 const int kMaxRestartAttempts = 10;
26 const char kPrivetDeviceTypeDnsString[] = "\x07_privet";
27
28 void GetNetworkListOnFileThread(
29 const base::Callback<void(const net::NetworkInterfaceList&)> callback) {
30 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
31 net::NetworkInterfaceList networks;
32 if (!GetNetworkList(&networks, net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES))
33 return;
34
35 net::NetworkInterfaceList ip4_networks;
36 for (size_t i = 0; i < networks.size(); ++i) {
37 net::AddressFamily address_family =
38 net::GetAddressFamily(networks[i].address);
39 if (address_family == net::ADDRESS_FAMILY_IPV4 &&
40 networks[i].prefix_length >= 24) {
41 ip4_networks.push_back(networks[i]);
42 }
43 }
44
45 net::IPAddressNumber localhost_prefix(4, 0);
46 localhost_prefix[0] = 127;
47 ip4_networks.push_back(
48 net::NetworkInterface("lo",
49 "lo",
50 0,
51 net::NetworkChangeNotifier::CONNECTION_UNKNOWN,
52 localhost_prefix,
53 8,
54 net::IP_ADDRESS_ATTRIBUTE_NONE));
55 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
56 base::Bind(callback, ip4_networks));
57 }
58
59 } // namespace
60
61 namespace local_discovery {
62
63 PrivetTrafficDetector::PrivetTrafficDetector(
64 net::AddressFamily address_family,
65 const base::Closure& on_traffic_detected)
66 : on_traffic_detected_(on_traffic_detected),
67 callback_runner_(base::MessageLoop::current()->task_runner()),
68 address_family_(address_family),
69 io_buffer_(
70 new net::IOBufferWithSize(net::dns_protocol::kMaxMulticastSize)),
71 restart_attempts_(kMaxRestartAttempts),
72 weak_ptr_factory_(this) {
73 }
74
75 void PrivetTrafficDetector::Start() {
76 content::BrowserThread::PostTask(
77 content::BrowserThread::IO,
78 FROM_HERE,
79 base::Bind(&PrivetTrafficDetector::StartOnIOThread,
80 weak_ptr_factory_.GetWeakPtr()));
81 }
82
83 PrivetTrafficDetector::~PrivetTrafficDetector() {
84 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
85 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
86 }
87
88 void PrivetTrafficDetector::StartOnIOThread() {
89 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
90 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
91 ScheduleRestart();
92 }
93
94 void PrivetTrafficDetector::OnNetworkChanged(
95 net::NetworkChangeNotifier::ConnectionType type) {
96 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
97 restart_attempts_ = kMaxRestartAttempts;
98 if (type != net::NetworkChangeNotifier::CONNECTION_NONE)
99 ScheduleRestart();
100 }
101
102 void PrivetTrafficDetector::ScheduleRestart() {
103 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
104 socket_.reset();
105 weak_ptr_factory_.InvalidateWeakPtrs();
106 content::BrowserThread::PostDelayedTask(
107 content::BrowserThread::FILE,
108 FROM_HERE,
109 base::Bind(&GetNetworkListOnFileThread,
110 base::Bind(&PrivetTrafficDetector::Restart,
111 weak_ptr_factory_.GetWeakPtr())),
112 base::TimeDelta::FromSeconds(3));
113 }
114
115 void PrivetTrafficDetector::Restart(const net::NetworkInterfaceList& networks) {
116 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
117 networks_ = networks;
118 if (Bind() < net::OK || DoLoop(0) < net::OK) {
119 if ((restart_attempts_--) > 0)
120 ScheduleRestart();
121 } else {
122 // Reset on success.
123 restart_attempts_ = kMaxRestartAttempts;
124 }
125 }
126
127 int PrivetTrafficDetector::Bind() {
128 if (!start_time_.is_null()) {
129 base::TimeDelta time_delta = base::Time::Now() - start_time_;
130 UMA_HISTOGRAM_LONG_TIMES("LocalDiscovery.DetectorRestartTime", time_delta);
131 }
132 start_time_ = base::Time::Now();
133 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
134 socket_.reset(new net::UDPServerSocket(NULL, net::NetLog::Source()));
135 net::IPEndPoint multicast_addr = net::GetMDnsIPEndPoint(address_family_);
136 net::IPAddressNumber address_any(multicast_addr.address().size());
137 net::IPEndPoint bind_endpoint(address_any, multicast_addr.port());
138 socket_->AllowAddressReuse();
139 int rv = socket_->Listen(bind_endpoint);
140 if (rv < net::OK)
141 return rv;
142 socket_->SetMulticastLoopbackMode(false);
143 return socket_->JoinGroup(multicast_addr.address());
144 }
145
146 bool PrivetTrafficDetector::IsSourceAcceptable() const {
147 for (size_t i = 0; i < networks_.size(); ++i) {
148 if (net::IPNumberMatchesPrefix(recv_addr_.address(), networks_[i].address,
149 networks_[i].prefix_length)) {
150 return true;
151 }
152 }
153 return false;
154 }
155
156 bool PrivetTrafficDetector::IsPrivetPacket(int rv) const {
157 if (rv <= static_cast<int>(sizeof(net::dns_protocol::Header)) ||
158 !IsSourceAcceptable()) {
159 return false;
160 }
161
162 const char* buffer_begin = io_buffer_->data();
163 const char* buffer_end = buffer_begin + rv;
164 const net::dns_protocol::Header* header =
165 reinterpret_cast<const net::dns_protocol::Header*>(buffer_begin);
166 // Check if response packet.
167 if (!(header->flags & base::HostToNet16(net::dns_protocol::kFlagResponse)))
168 return false;
169 const char* substring_begin = kPrivetDeviceTypeDnsString;
170 const char* substring_end = substring_begin +
171 arraysize(kPrivetDeviceTypeDnsString) - 1;
172 // Check for expected substring, any Privet device must include this.
173 return std::search(buffer_begin, buffer_end, substring_begin,
174 substring_end) != buffer_end;
175 }
176
177 int PrivetTrafficDetector::DoLoop(int rv) {
178 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
179 do {
180 if (IsPrivetPacket(rv)) {
181 socket_.reset();
182 callback_runner_->PostTask(FROM_HERE, on_traffic_detected_);
183 base::TimeDelta time_delta = base::Time::Now() - start_time_;
184 UMA_HISTOGRAM_LONG_TIMES("LocalDiscovery.DetectorTriggerTime",
185 time_delta);
186 return net::OK;
187 }
188
189 rv = socket_->RecvFrom(
190 io_buffer_.get(),
191 io_buffer_->size(),
192 &recv_addr_,
193 base::Bind(base::IgnoreResult(&PrivetTrafficDetector::DoLoop),
194 base::Unretained(this)));
195 } while (rv > 0);
196
197 if (rv != net::ERR_IO_PENDING)
198 return rv;
199
200 return net::OK;
201 }
202
203 } // namespace local_discovery
OLDNEW
« no previous file with comments | « chrome/browser/local_discovery/privet_traffic_detector.h ('k') | chrome/browser/local_discovery/privet_url_fetcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698