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

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: Fixed unit test. 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 version.Version().c_str(), 95 version.Version().c_str(),
96 version.OSType().c_str())); 96 version.OSType().c_str()));
97 // 1500 is a good MTU value for most Ethernet LANs. 97 // 1500 is a good MTU value for most Ethernet LANs.
98 DCHECK(request.size() <= 1500); 98 DCHECK(request.size() <= 1500);
99 return request; 99 return request;
100 } 100 }
101 101
102 } // namespace 102 } // namespace
103 103
104 DialServiceImpl::DialServiceImpl(net::NetLog* net_log) 104 DialServiceImpl::DialServiceImpl(net::NetLog* net_log)
105 : is_writing_(false), is_reading_(false), discovery_active_(false), 105 : is_writing_(false),
106 num_requests_sent_(0) { 106 is_reading_(false),
107 discovery_active_(false),
108 num_requests_sent_(0),
109 max_requests_(kDialMaxRequests),
110 finish_delay_(TimeDelta::FromMilliseconds((kDialMaxRequests - 1) *
111 kDialRequestIntervalMillis) +
112 TimeDelta::FromSeconds(kDialResponseTimeoutSecs)),
113 request_interval_(TimeDelta::FromMilliseconds(kDialRequestIntervalMillis))
114 {
107 IPAddressNumber address; 115 IPAddressNumber address;
108 bool result = net::ParseIPLiteralToNumber(kDialRequestAddress, &address); 116 bool result = net::ParseIPLiteralToNumber(kDialRequestAddress, &address);
109 DCHECK(result); 117 DCHECK(result);
110 send_address_ = IPEndPoint(address, kDialRequestPort); 118 send_address_ = IPEndPoint(address, kDialRequestPort);
111 send_buffer_ = new StringIOBuffer(BuildRequest()); 119 send_buffer_ = new StringIOBuffer(BuildRequest());
112 net_log_ = net_log; 120 net_log_ = net_log;
113 net_log_source_.type = net::NetLog::SOURCE_UDP_SOCKET; 121 net_log_source_.type = net::NetLog::SOURCE_UDP_SOCKET;
114 net_log_source_.id = net_log_->NextID(); 122 net_log_source_.id = net_log_->NextID();
115 finish_delay_ = TimeDelta::FromMilliseconds((kDialNumRequests - 1) *
116 kDialRequestIntervalMillis) +
117 TimeDelta::FromSeconds(kDialResponseTimeoutSecs);
118 } 123 }
119 124
120 DialServiceImpl::~DialServiceImpl() { 125 DialServiceImpl::~DialServiceImpl() {
121 DCHECK(thread_checker_.CalledOnValidThread()); 126 DCHECK(thread_checker_.CalledOnValidThread());
122 } 127 }
123 128
124 void DialServiceImpl::AddObserver(Observer* observer) { 129 void DialServiceImpl::AddObserver(Observer* observer) {
125 DCHECK(thread_checker_.CalledOnValidThread()); 130 DCHECK(thread_checker_.CalledOnValidThread());
126 observer_list_.AddObserver(observer); 131 observer_list_.AddObserver(observer);
127 } 132 }
128 133
129 void DialServiceImpl::RemoveObserver(Observer* observer) { 134 void DialServiceImpl::RemoveObserver(Observer* observer) {
130 DCHECK(thread_checker_.CalledOnValidThread()); 135 DCHECK(thread_checker_.CalledOnValidThread());
131 observer_list_.RemoveObserver(observer); 136 observer_list_.RemoveObserver(observer);
132 } 137 }
133 138
134 bool DialServiceImpl::HasObserver(Observer* observer) { 139 bool DialServiceImpl::HasObserver(Observer* observer) {
135 DCHECK(thread_checker_.CalledOnValidThread()); 140 DCHECK(thread_checker_.CalledOnValidThread());
136 return observer_list_.HasObserver(observer); 141 return observer_list_.HasObserver(observer);
137 } 142 }
138 143
139 bool DialServiceImpl::Discover() { 144 bool DialServiceImpl::Discover() {
140 DCHECK(thread_checker_.CalledOnValidThread()); 145 DCHECK(thread_checker_.CalledOnValidThread());
141 if (discovery_active_) 146 if (discovery_active_)
142 return false; 147 return false;
143 discovery_active_ = true; 148 discovery_active_ = true;
144 149
145 DVLOG(1) << "Discovery started."; 150 DVLOG(1) << "Discovery started.";
146 151
147 // TODO(mfoltz): Send multiple requests. 152 StartDiscovery();
148 StartRequest();
149 return true; 153 return true;
150 } 154 }
151 155
152 void DialServiceImpl::FinishDiscovery() { 156 void DialServiceImpl::StartDiscovery() {
153 DCHECK(thread_checker_.CalledOnValidThread()); 157 DCHECK(thread_checker_.CalledOnValidThread());
154 DCHECK(discovery_active_); 158 DCHECK(discovery_active_);
155 DVLOG(1) << "Discovery finished."; 159 if (socket_.get())
156 CloseSocket(); 160 return;
157 finish_timer_.Stop(); 161
158 discovery_active_ = false; 162 // TODO(mfoltz): Add a net::NetworkChangeNotifier() to listen for connection
justinlin 2013/02/07 09:03:24 This TODO no longer needed.
mark a. foltz 2013/02/07 22:36:55 Done.
159 num_requests_sent_ = 0; 163 // type/IP address changes, and notify via observer. Also sanity check the
160 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this)); 164 // connection type, i.e. !IsOffline && !IsCellular
165 // http://crbug.com/165290
166 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
167 &DialServiceImpl::DoGetNetworkList, this));
161 } 168 }
162 169
163 bool DialServiceImpl::BindAndWriteSocket( 170 bool DialServiceImpl::BindSocketAndSendRequest(
164 const NetworkInterface& bind_interface) { 171 const IPAddressNumber& bind_ip_address) {
165 DCHECK(thread_checker_.CalledOnValidThread()); 172 DCHECK(thread_checker_.CalledOnValidThread());
166 DCHECK(!socket_.get()); 173 DCHECK(!socket_.get());
167 174
168 net::RandIntCallback rand_cb = base::Bind(&base::RandInt); 175 net::RandIntCallback rand_cb = base::Bind(&base::RandInt);
169 socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND, 176 socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND,
170 rand_cb, 177 rand_cb,
171 net_log_, 178 net_log_,
172 net_log_source_)); 179 net_log_source_));
173 socket_->AllowBroadcast(); 180 socket_->AllowBroadcast();
174 181
175 // Schedule a timer to finish the discovery process (and close the socket). 182 // Schedule a timer to finish the discovery process (and close the socket).
176 finish_timer_.Start(FROM_HERE, 183 if (finish_delay_ > TimeDelta::FromSeconds(0)) {
177 finish_delay_, 184 finish_timer_.Start(FROM_HERE,
178 this, 185 finish_delay_,
179 &DialServiceImpl::FinishDiscovery); 186 this,
187 &DialServiceImpl::FinishDiscovery);
188 }
180 189
181 // 0 means bind a random port 190 // 0 means bind a random port
182 IPEndPoint address(bind_interface.address, 0); 191 IPEndPoint address(bind_ip_address, 0);
183 192
184 if (!CheckResult("Bind", socket_->Bind(address))) 193 if (!CheckResult("Bind", socket_->Bind(address)))
185 return false; 194 return false;
186 195
196 recv_buffer_ = new IOBufferWithSize(kDialRecvBufferSize);
197 if (!ReadSocket()) {
justinlin 2013/02/07 09:03:24 no braces
mark a. foltz 2013/02/07 22:36:55 Done.
198 return false;
199 }
200 SendOneRequest();
201 return true;
202 }
203
204 void DialServiceImpl::SendOneRequest() {
205 if (num_requests_sent_ == max_requests_) {
206 request_timer_.Stop();
207 return;
208 }
209 num_requests_sent_++;
187 if (!socket_.get()) { 210 if (!socket_.get()) {
188 DLOG(WARNING) << "Socket not connected."; 211 DLOG(WARNING) << "Socket not connected.";
189 return false; 212 return;
190 } 213 }
191
192 recv_buffer_ = new IOBufferWithSize(kDialRecvBufferSize);
193 ReadSocket();
194
195 if (is_writing_) { 214 if (is_writing_) {
196 DVLOG(1) << "Already writing."; 215 DVLOG(1) << "Already writing.";
197 return false; 216 return;
198 } 217 }
218 DVLOG(1) << "Sending request " << num_requests_sent_ << "/"
219 << max_requests_;
199 is_writing_ = true; 220 is_writing_ = true;
200 int result = socket_->SendTo( 221 int result = socket_->SendTo(
201 send_buffer_.get(), 222 send_buffer_.get(),
202 send_buffer_->size(), send_address_, 223 send_buffer_->size(), send_address_,
203 base::Bind(&DialServiceImpl::OnSocketWrite, this)); 224 base::Bind(&DialServiceImpl::OnSocketWrite, this));
204 bool result_ok = CheckResult("SendTo", result); 225 bool result_ok = CheckResult("SendTo", result);
205 if (result_ok && result > 0) { 226 if (result_ok && result > 0) {
206 // Synchronous write. 227 // Synchronous write.
207 OnSocketWrite(result); 228 OnSocketWrite(result);
208 } 229 }
209 return result_ok; 230 return;
210 }
211
212 void DialServiceImpl::StartRequest() {
213 DCHECK(thread_checker_.CalledOnValidThread());
214 DCHECK(discovery_active_);
215 if (socket_.get())
216 return;
217
218 // TODO(mfoltz): Add a net::NetworkChangeNotifier() to listen for connection
219 // type/IP address changes, and notify via observer. Also sanity check the
220 // connection type, i.e. !IsOffline && !IsCellular
221 // http://crbug.com/165290
222 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
223 &DialServiceImpl::DoGetNetworkList, this));
224 } 231 }
225 232
226 void DialServiceImpl::OnSocketWrite(int result) { 233 void DialServiceImpl::OnSocketWrite(int result) {
227 DCHECK(thread_checker_.CalledOnValidThread()); 234 DCHECK(thread_checker_.CalledOnValidThread());
228 is_writing_ = false; 235 is_writing_ = false;
229 if (!CheckResult("OnSocketWrite", result)) 236 if (!CheckResult("OnSocketWrite", result))
230 return; 237 return;
231
232 if (result != send_buffer_->size()) { 238 if (result != send_buffer_->size()) {
233 DLOG(ERROR) << "Sent " << result << " chars, expected " 239 DLOG(ERROR) << "Sent " << result << " chars, expected "
234 << send_buffer_->size() << " chars"; 240 << send_buffer_->size() << " chars";
235 } 241 }
236 // If discovery is inactive, no reason to notify observers. 242 // If discovery is inactive, no reason to notify observers.
237 if (!discovery_active_) { 243 if (!discovery_active_) {
238 DVLOG(1) << "Request sent after discovery finished. Ignoring."; 244 DVLOG(1) << "Request sent after discovery finished. Ignoring.";
239 return; 245 return;
240 } 246 }
241 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this)); 247 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this));
242 num_requests_sent_++; 248 // If we need to send additional requests, schedule a timer to do so.
249 if (num_requests_sent_ < max_requests_) {
250 if (request_interval_ <= TimeDelta::FromSeconds(0)) {
justinlin 2013/02/07 09:03:24 Is this check needed? Seems like scheduling a time
mark a. foltz 2013/02/07 22:36:55 Scheduling a zero-delay timer didn't result in a t
justinlin 2013/02/07 22:42:05 Ah, if it's for testing, then I think it's possibl
mark a. foltz 2013/02/08 00:04:50 Thanks for the tip. I wasn't able to use RunLoop
251 SendOneRequest();
252 } else if (num_requests_sent_ == 1) {
253 request_timer_.Start(FROM_HERE,
254 request_interval_,
255 this,
256 &DialServiceImpl::SendOneRequest);
257 } else {
258 DCHECK(request_timer_.IsRunning());
justinlin 2013/02/07 09:03:24 I'm not sure this DCHECK is valid. Since the DialS
mark a. foltz 2013/02/07 22:36:55 Good point. Removed.
259 }
260 }
243 } 261 }
244 262
245 bool DialServiceImpl::ReadSocket() { 263 bool DialServiceImpl::ReadSocket() {
246 DCHECK(thread_checker_.CalledOnValidThread()); 264 DCHECK(thread_checker_.CalledOnValidThread());
247 if (!socket_.get()) { 265 if (!socket_.get()) {
248 DLOG(WARNING) << "Socket not connected."; 266 DLOG(WARNING) << "Socket not connected.";
249 return false; 267 return false;
250 } 268 }
251 269
252 if (is_reading_) { 270 if (is_reading_) {
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 DVLOG(1) << "Malformed or missing " << kSsdpConfigIdHeader << ": " 382 DVLOG(1) << "Malformed or missing " << kSsdpConfigIdHeader << ": "
365 << config_id; 383 << config_id;
366 } 384 }
367 385
368 return true; 386 return true;
369 } 387 }
370 388
371 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) { 389 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) {
372 DCHECK(thread_checker_.CalledOnValidThread()); 390 DCHECK(thread_checker_.CalledOnValidThread());
373 if (!networks.size()) { 391 if (!networks.size()) {
374 DVLOG(1) << "No network interfaces found!"; 392 DVLOG(1) << "No valid network interfaces found!";
393 FinishDiscovery();
375 return; 394 return;
376 } 395 }
377 396
378 const NetworkInterface* interface = NULL; 397 const NetworkInterface* interface = NULL;
379 // Returns the first IPv4 address found. If there is a need for discovery 398 // Returns the first IPv4 address found. If there is a need for discovery
380 // across multiple networks, we could manage multiple sockets. 399 // across multiple networks, we could manage multiple sockets.
381 400
382 // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286 401 // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286
383 for (NetworkInterfaceList::const_iterator iter = networks.begin(); 402 for (NetworkInterfaceList::const_iterator iter = networks.begin();
384 iter != networks.end(); iter++) { 403 iter != networks.end(); iter++) {
385 DVLOG(1) << "Found " << iter->name << ", " 404 DVLOG(1) << "Found " << iter->name << ", "
386 << net::IPAddressToString(iter->address); 405 << net::IPAddressToString(iter->address);
387 if (iter->address.size() == net::kIPv4AddressSize) { 406 if (iter->address.size() == net::kIPv4AddressSize) {
388 interface = &*iter; 407 interface = &*iter;
389 break; 408 break;
390 } 409 }
391 } 410 }
392 411
393 if (interface == NULL) { 412 if (interface == NULL) {
394 DVLOG(1) << "Could not find a valid interface to bind."; 413 DVLOG(1) << "Could not find a valid interface to bind.";
414 FinishDiscovery();
395 } else { 415 } else {
396 BindAndWriteSocket(*interface); 416 BindSocketAndSendRequest(interface->address);
397 } 417 }
398 } 418 }
399 419
400 void DialServiceImpl::DoGetNetworkList() { 420 void DialServiceImpl::DoGetNetworkList() {
401 NetworkInterfaceList list; 421 NetworkInterfaceList list;
402 bool success = net::GetNetworkList(&list); 422 bool success = net::GetNetworkList(&list);
403 if (!success) { 423 if (!success) {
404 DVLOG(1) << "Could not retrieve network list!"; 424 DVLOG(1) << "Could not retrieve network list!";
405 return; 425 list.clear();
justinlin 2013/02/07 09:03:24 This isn't needed as the vector is already initial
mark a. foltz 2013/02/07 22:36:55 Done. Will rebase.
406 } 426 }
407 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( 427 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
408 &DialServiceImpl::SendNetworkList, this, list)); 428 &DialServiceImpl::SendNetworkList, this, list));
409 } 429 }
410 430
431 void DialServiceImpl::FinishDiscovery() {
432 DCHECK(thread_checker_.CalledOnValidThread());
433 DCHECK(discovery_active_);
434 DVLOG(1) << "Discovery finished.";
435 CloseSocket();
436 finish_timer_.Stop();
437 request_timer_.Stop();
438 discovery_active_ = false;
439 num_requests_sent_ = 0;
440 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this));
441 }
442
411 void DialServiceImpl::CloseSocket() { 443 void DialServiceImpl::CloseSocket() {
412 DCHECK(thread_checker_.CalledOnValidThread()); 444 DCHECK(thread_checker_.CalledOnValidThread());
413 is_reading_ = false; 445 is_reading_ = false;
414 is_writing_ = false; 446 is_writing_ = false;
415 if (!socket_.get()) 447 if (!socket_.get())
416 return; 448 return;
417 socket_.reset(); 449 socket_.reset();
418 } 450 }
419 451
420 bool DialServiceImpl::CheckResult(const char* operation, int result) { 452 bool DialServiceImpl::CheckResult(const char* operation, int result) {
421 DCHECK(thread_checker_.CalledOnValidThread()); 453 DCHECK(thread_checker_.CalledOnValidThread());
422 DVLOG(1) << "Operation " << operation << " result " << result; 454 DVLOG(1) << "Operation " << operation << " result " << result;
423 if (result < net::OK && result != net::ERR_IO_PENDING) { 455 if (result < net::OK && result != net::ERR_IO_PENDING) {
424 CloseSocket(); 456 CloseSocket();
425 std::string error_str(net::ErrorToString(result)); 457 std::string error_str(net::ErrorToString(result));
426 DVLOG(0) << "dial socket error: " << error_str; 458 DVLOG(0) << "dial socket error: " << error_str;
427 FOR_EACH_OBSERVER(Observer, observer_list_, OnError(this, error_str)); 459 FOR_EACH_OBSERVER(Observer, observer_list_, OnError(this, error_str));
428 return false; 460 return false;
429 } 461 }
430 return true; 462 return true;
431 } 463 }
432 464
433 } // namespace extensions 465 } // 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