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

Side by Side Diff: chrome/browser/extensions/api/dial/dial_service.cc

Issue 12150002: - Invoke FinishDiscovery() if no network interfaces are detected. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge with r181795 Created 7 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/dial/dial_service.h" 5 #include "chrome/browser/extensions/api/dial/dial_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
(...skipping 24 matching lines...) Expand all
35 using net::IPEndPoint; 35 using net::IPEndPoint;
36 using net::NetworkInterface; 36 using net::NetworkInterface;
37 using net::NetworkInterfaceList; 37 using net::NetworkInterfaceList;
38 using net::StringIOBuffer; 38 using net::StringIOBuffer;
39 using net::UDPSocket; 39 using net::UDPSocket;
40 40
41 namespace extensions { 41 namespace extensions {
42 42
43 namespace { 43 namespace {
44 44
45 // The total number of requests to make. 45 // The total number of requests to make per discovery cycle.
46 const int kDialNumRequests = 1; 46 const int kDialMaxRequests = 4;
47 47
48 // The interval to wait between successive requests. 48 // The interval to wait between successive requests.
49 const int kDialRequestIntervalMillis = 1000; 49 const int kDialRequestIntervalMillis = 1000;
50 50
51 // The timeout (MX) set for responses. 51 // The timeout (MX) set for responses.
52 const int kDialResponseTimeoutSecs = 2; 52 const int kDialResponseTimeoutSecs = 2;
53 53
54 // The multicast IP address for discovery. 54 // The multicast IP address for discovery.
55 const char kDialRequestAddress[] = "239.255.255.250"; 55 const char kDialRequestAddress[] = "239.255.255.250";
56 56
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 bool success = net::GetNetworkList(&list); 106 bool success = net::GetNetworkList(&list);
107 if (!success) 107 if (!success)
108 DVLOG(1) << "Could not retrieve network list!"; 108 DVLOG(1) << "Could not retrieve network list!";
109 109
110 loop->PostTask(FROM_HERE, base::Bind(cb, list)); 110 loop->PostTask(FROM_HERE, base::Bind(cb, list));
111 } 111 }
112 112
113 } // namespace 113 } // namespace
114 114
115 DialServiceImpl::DialServiceImpl(net::NetLog* net_log) 115 DialServiceImpl::DialServiceImpl(net::NetLog* net_log)
116 : is_writing_(false), is_reading_(false), discovery_active_(false), 116 : is_writing_(false),
117 num_requests_sent_(0) { 117 is_reading_(false),
118 discovery_active_(false),
119 num_requests_sent_(0),
120 max_requests_(kDialMaxRequests),
121 finish_delay_(TimeDelta::FromMilliseconds((kDialMaxRequests - 1) *
122 kDialRequestIntervalMillis) +
123 TimeDelta::FromSeconds(kDialResponseTimeoutSecs)),
124 request_interval_(TimeDelta::FromMilliseconds(kDialRequestIntervalMillis))
125 {
118 IPAddressNumber address; 126 IPAddressNumber address;
119 bool result = net::ParseIPLiteralToNumber(kDialRequestAddress, &address); 127 bool result = net::ParseIPLiteralToNumber(kDialRequestAddress, &address);
120 DCHECK(result); 128 DCHECK(result);
121 send_address_ = IPEndPoint(address, kDialRequestPort); 129 send_address_ = IPEndPoint(address, kDialRequestPort);
122 send_buffer_ = new StringIOBuffer(BuildRequest()); 130 send_buffer_ = new StringIOBuffer(BuildRequest());
123 net_log_ = net_log; 131 net_log_ = net_log;
124 net_log_source_.type = net::NetLog::SOURCE_UDP_SOCKET; 132 net_log_source_.type = net::NetLog::SOURCE_UDP_SOCKET;
125 net_log_source_.id = net_log_->NextID(); 133 net_log_source_.id = net_log_->NextID();
126 finish_delay_ = TimeDelta::FromMilliseconds((kDialNumRequests - 1) *
127 kDialRequestIntervalMillis) +
128 TimeDelta::FromSeconds(kDialResponseTimeoutSecs);
129 } 134 }
130 135
131 DialServiceImpl::~DialServiceImpl() { 136 DialServiceImpl::~DialServiceImpl() {
132 DCHECK(thread_checker_.CalledOnValidThread()); 137 DCHECK(thread_checker_.CalledOnValidThread());
133 } 138 }
134 139
135 void DialServiceImpl::AddObserver(Observer* observer) { 140 void DialServiceImpl::AddObserver(Observer* observer) {
136 DCHECK(thread_checker_.CalledOnValidThread()); 141 DCHECK(thread_checker_.CalledOnValidThread());
137 observer_list_.AddObserver(observer); 142 observer_list_.AddObserver(observer);
138 } 143 }
139 144
140 void DialServiceImpl::RemoveObserver(Observer* observer) { 145 void DialServiceImpl::RemoveObserver(Observer* observer) {
141 DCHECK(thread_checker_.CalledOnValidThread()); 146 DCHECK(thread_checker_.CalledOnValidThread());
142 observer_list_.RemoveObserver(observer); 147 observer_list_.RemoveObserver(observer);
143 } 148 }
144 149
145 bool DialServiceImpl::HasObserver(Observer* observer) { 150 bool DialServiceImpl::HasObserver(Observer* observer) {
146 DCHECK(thread_checker_.CalledOnValidThread()); 151 DCHECK(thread_checker_.CalledOnValidThread());
147 return observer_list_.HasObserver(observer); 152 return observer_list_.HasObserver(observer);
148 } 153 }
149 154
150 bool DialServiceImpl::Discover() { 155 bool DialServiceImpl::Discover() {
151 DCHECK(thread_checker_.CalledOnValidThread()); 156 DCHECK(thread_checker_.CalledOnValidThread());
152 if (discovery_active_) 157 if (discovery_active_)
153 return false; 158 return false;
154 discovery_active_ = true; 159 discovery_active_ = true;
155 160
156 DVLOG(1) << "Discovery started."; 161 DVLOG(1) << "Discovery started.";
157 162
158 // TODO(mfoltz): Send multiple requests. 163 StartDiscovery();
159 StartRequest();
160 return true; 164 return true;
161 } 165 }
162 166
163 void DialServiceImpl::FinishDiscovery() { 167 void DialServiceImpl::StartDiscovery() {
164 DCHECK(thread_checker_.CalledOnValidThread()); 168 DCHECK(thread_checker_.CalledOnValidThread());
165 DCHECK(discovery_active_); 169 DCHECK(discovery_active_);
166 DVLOG(1) << "Discovery finished."; 170 if (socket_.get())
167 CloseSocket(); 171 return;
168 finish_timer_.Stop(); 172
169 discovery_active_ = false; 173 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
170 num_requests_sent_ = 0; 174 &GetNetworkListOnFileThread,
171 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this)); 175 base::MessageLoopProxy::current(), base::Bind(
176 &DialServiceImpl::SendNetworkList, AsWeakPtr())));
172 } 177 }
173 178
174 bool DialServiceImpl::BindAndWriteSocket( 179 bool DialServiceImpl::BindSocketAndSendRequest(
175 const NetworkInterface& bind_interface) { 180 const IPAddressNumber& bind_ip_address) {
176 DCHECK(thread_checker_.CalledOnValidThread()); 181 DCHECK(thread_checker_.CalledOnValidThread());
177 DCHECK(!socket_.get()); 182 DCHECK(!socket_.get());
178 183
179 net::RandIntCallback rand_cb = base::Bind(&base::RandInt); 184 net::RandIntCallback rand_cb = base::Bind(&base::RandInt);
180 socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND, 185 socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND,
181 rand_cb, 186 rand_cb,
182 net_log_, 187 net_log_,
183 net_log_source_)); 188 net_log_source_));
184 socket_->AllowBroadcast(); 189 socket_->AllowBroadcast();
185 190
186 // Schedule a timer to finish the discovery process (and close the socket). 191 // Schedule a timer to finish the discovery process (and close the socket).
187 finish_timer_.Start(FROM_HERE, 192 if (finish_delay_ > TimeDelta::FromSeconds(0)) {
188 finish_delay_, 193 finish_timer_.Start(FROM_HERE,
189 this, 194 finish_delay_,
190 &DialServiceImpl::FinishDiscovery); 195 this,
196 &DialServiceImpl::FinishDiscovery);
197 }
191 198
192 // 0 means bind a random port 199 // 0 means bind a random port
193 IPEndPoint address(bind_interface.address, 0); 200 IPEndPoint address(bind_ip_address, 0);
194 201
195 if (!CheckResult("Bind", socket_->Bind(address))) 202 if (!CheckResult("Bind", socket_->Bind(address)))
196 return false; 203 return false;
197 204
198 DCHECK(socket_.get()); 205 DCHECK(socket_.get());
199 206
200 recv_buffer_ = new IOBufferWithSize(kDialRecvBufferSize); 207 recv_buffer_ = new IOBufferWithSize(kDialRecvBufferSize);
201 ReadSocket(); 208 if (!ReadSocket())
209 return false;
210 SendOneRequest();
211 return true;
212 }
213
214 void DialServiceImpl::SendOneRequest() {
215 if (num_requests_sent_ == max_requests_) {
216 request_timer_.Stop();
217 return;
218 }
219 num_requests_sent_++;
220 if (!socket_.get()) {
221 DLOG(WARNING) << "Socket not connected.";
222 return;
223 }
202 224
203 if (is_writing_) { 225 if (is_writing_) {
204 DVLOG(1) << "Already writing."; 226 DVLOG(1) << "Already writing.";
205 return false; 227 return;
206 } 228 }
229 DVLOG(1) << "Sending request " << num_requests_sent_ << "/"
230 << max_requests_;
207 is_writing_ = true; 231 is_writing_ = true;
208 int result = socket_->SendTo( 232 int result = socket_->SendTo(
209 send_buffer_.get(), send_buffer_->size(), send_address_, 233 send_buffer_.get(), send_buffer_->size(), send_address_,
210 base::Bind(&DialServiceImpl::OnSocketWrite, AsWeakPtr())); 234 base::Bind(&DialServiceImpl::OnSocketWrite, AsWeakPtr()));
211 bool result_ok = CheckResult("SendTo", result); 235 bool result_ok = CheckResult("SendTo", result);
212 if (result_ok && result > 0) { 236 if (result_ok && result > 0) {
213 // Synchronous write. 237 // Synchronous write.
214 OnSocketWrite(result); 238 OnSocketWrite(result);
215 } 239 }
216 return result_ok;
217 }
218
219 void DialServiceImpl::StartRequest() {
220 DCHECK(thread_checker_.CalledOnValidThread());
221 DCHECK(discovery_active_);
222 if (socket_.get())
223 return;
224
225 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
226 &GetNetworkListOnFileThread,
227 base::MessageLoopProxy::current(), base::Bind(
228 &DialServiceImpl::SendNetworkList, AsWeakPtr())));
229 }
230
231 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 if (!networks.size()) {
234 DVLOG(1) << "No network interfaces found!";
235 FOR_EACH_OBSERVER(
236 Observer, observer_list_, OnError(this, DIAL_SERVICE_NO_INTERFACES));
237 return;
238 }
239
240 const NetworkInterface* interface = NULL;
241 // Returns the first IPv4 address found. If there is a need for discovery
242 // across multiple networks, we could manage multiple sockets.
243
244 // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286
245 for (NetworkInterfaceList::const_iterator iter = networks.begin();
246 iter != networks.end(); ++iter) {
247 DVLOG(1) << "Found " << iter->name << ", "
248 << net::IPAddressToString(iter->address);
249 if (iter->address.size() == net::kIPv4AddressSize) {
250 interface = &*iter;
251 break;
252 }
253 }
254
255 if (interface == NULL) {
256 DVLOG(1) << "Could not find a valid interface to bind.";
257 } else {
258 BindAndWriteSocket(*interface);
259 }
260 } 240 }
261 241
262 void DialServiceImpl::OnSocketWrite(int result) { 242 void DialServiceImpl::OnSocketWrite(int result) {
263 DCHECK(thread_checker_.CalledOnValidThread()); 243 DCHECK(thread_checker_.CalledOnValidThread());
264 is_writing_ = false; 244 is_writing_ = false;
265 if (!CheckResult("OnSocketWrite", result)) 245 if (!CheckResult("OnSocketWrite", result))
266 return; 246 return;
267 247
268 if (result != send_buffer_->size()) { 248 if (result != send_buffer_->size()) {
269 DLOG(ERROR) << "Sent " << result << " chars, expected " 249 DLOG(ERROR) << "Sent " << result << " chars, expected "
270 << send_buffer_->size() << " chars"; 250 << send_buffer_->size() << " chars";
271 } 251 }
272 // If discovery is inactive, no reason to notify observers. 252 // If discovery is inactive, no reason to notify observers.
273 if (!discovery_active_) { 253 if (!discovery_active_) {
274 DVLOG(1) << "Request sent after discovery finished. Ignoring."; 254 DVLOG(1) << "Request sent after discovery finished. Ignoring.";
275 return; 255 return;
276 } 256 }
277 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this)); 257 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this));
278 num_requests_sent_++; 258 // If we need to send additional requests, schedule a timer to do so.
259 if (num_requests_sent_ < max_requests_ && num_requests_sent_ == 1) {
260 request_timer_.Start(FROM_HERE,
261 request_interval_,
262 this,
263 &DialServiceImpl::SendOneRequest);
264 }
279 } 265 }
280 266
281 bool DialServiceImpl::ReadSocket() { 267 bool DialServiceImpl::ReadSocket() {
282 DCHECK(thread_checker_.CalledOnValidThread()); 268 DCHECK(thread_checker_.CalledOnValidThread());
283 if (!socket_.get()) { 269 if (!socket_.get()) {
284 DLOG(WARNING) << "Socket not connected."; 270 DLOG(WARNING) << "Socket not connected.";
285 return false; 271 return false;
286 } 272 }
287 273
288 if (is_reading_) { 274 if (is_reading_) {
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 base::StringToInt(config_id, &config_id_int)) { 383 base::StringToInt(config_id, &config_id_int)) {
398 device->set_config_id(config_id_int); 384 device->set_config_id(config_id_int);
399 } else { 385 } else {
400 DVLOG(1) << "Malformed or missing " << kSsdpConfigIdHeader << ": " 386 DVLOG(1) << "Malformed or missing " << kSsdpConfigIdHeader << ": "
401 << config_id; 387 << config_id;
402 } 388 }
403 389
404 return true; 390 return true;
405 } 391 }
406 392
393 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) {
394 DCHECK(thread_checker_.CalledOnValidThread());
395 const NetworkInterface* interface = NULL;
396 // Returns the first IPv4 address found. If there is a need for discovery
397 // across multiple networks, we could manage multiple sockets.
398
399 // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286
400 for (NetworkInterfaceList::const_iterator iter = networks.begin();
401 iter != networks.end(); ++iter) {
402 DVLOG(1) << "Found " << iter->name << ", "
403 << net::IPAddressToString(iter->address);
404 if (iter->address.size() == net::kIPv4AddressSize) {
405 interface = &*iter;
406 break;
407 }
408 }
409
410 if (interface == NULL) {
411 DVLOG(1) << "Could not find a valid interface to bind.";
412 FinishDiscovery();
413 } else {
414 BindSocketAndSendRequest(interface->address);
415 }
416 }
417
418 void DialServiceImpl::FinishDiscovery() {
419 DCHECK(thread_checker_.CalledOnValidThread());
420 DCHECK(discovery_active_);
421 DVLOG(1) << "Discovery finished.";
422 CloseSocket();
423 finish_timer_.Stop();
424 request_timer_.Stop();
425 discovery_active_ = false;
426 num_requests_sent_ = 0;
427 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this));
428 }
429
407 void DialServiceImpl::CloseSocket() { 430 void DialServiceImpl::CloseSocket() {
408 DCHECK(thread_checker_.CalledOnValidThread()); 431 DCHECK(thread_checker_.CalledOnValidThread());
409 is_reading_ = false; 432 is_reading_ = false;
410 is_writing_ = false; 433 is_writing_ = false;
411 socket_.reset(); 434 socket_.reset();
412 } 435 }
413 436
414 bool DialServiceImpl::CheckResult(const char* operation, int result) { 437 bool DialServiceImpl::CheckResult(const char* operation, int result) {
415 DCHECK(thread_checker_.CalledOnValidThread()); 438 DCHECK(thread_checker_.CalledOnValidThread());
416 DVLOG(1) << "Operation " << operation << " result " << result; 439 DVLOG(1) << "Operation " << operation << " result " << result;
417 if (result < net::OK && result != net::ERR_IO_PENDING) { 440 if (result < net::OK && result != net::ERR_IO_PENDING) {
418 CloseSocket(); 441 CloseSocket();
419 std::string error_str(net::ErrorToString(result)); 442 std::string error_str(net::ErrorToString(result));
420 DVLOG(0) << "dial socket error: " << error_str; 443 DVLOG(0) << "dial socket error: " << error_str;
421 // TODO(justinlin): More granular socket errors. 444 // TODO(justinlin): More granular socket errors.
422 FOR_EACH_OBSERVER( 445 FOR_EACH_OBSERVER(
423 Observer, observer_list_, OnError(this, DIAL_SERVICE_SOCKET_ERROR)); 446 Observer, observer_list_, OnError(this, DIAL_SERVICE_SOCKET_ERROR));
424 return false; 447 return false;
425 } 448 }
426 return true; 449 return true;
427 } 450 }
428 451
429 } // namespace extensions 452 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/api/dial/dial_service.h ('k') | chrome/browser/extensions/api/dial/dial_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698