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

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: Simplify DialService::SendNetworkList 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) +
justinlin 2013/02/08 08:56:20 Align this with the "(" above.
mark a. foltz 2013/02/08 22:07:58 Done.
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 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
159 num_requests_sent_ = 0; 163 &DialServiceImpl::DoGetNetworkList, this));
160 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this));
161 } 164 }
162 165
163 bool DialServiceImpl::BindAndWriteSocket( 166 bool DialServiceImpl::BindSocketAndSendRequest(
164 const NetworkInterface& bind_interface) { 167 const IPAddressNumber& bind_ip_address) {
165 DCHECK(thread_checker_.CalledOnValidThread()); 168 DCHECK(thread_checker_.CalledOnValidThread());
166 DCHECK(!socket_.get()); 169 DCHECK(!socket_.get());
167 170
168 net::RandIntCallback rand_cb = base::Bind(&base::RandInt); 171 net::RandIntCallback rand_cb = base::Bind(&base::RandInt);
169 socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND, 172 socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND,
170 rand_cb, 173 rand_cb,
171 net_log_, 174 net_log_,
172 net_log_source_)); 175 net_log_source_));
173 socket_->AllowBroadcast(); 176 socket_->AllowBroadcast();
174 177
175 // Schedule a timer to finish the discovery process (and close the socket). 178 // Schedule a timer to finish the discovery process (and close the socket).
176 finish_timer_.Start(FROM_HERE, 179 if (finish_delay_ > TimeDelta::FromSeconds(0)) {
177 finish_delay_, 180 finish_timer_.Start(FROM_HERE,
178 this, 181 finish_delay_,
179 &DialServiceImpl::FinishDiscovery); 182 this,
183 &DialServiceImpl::FinishDiscovery);
184 }
180 185
181 // 0 means bind a random port 186 // 0 means bind a random port
182 IPEndPoint address(bind_interface.address, 0); 187 IPEndPoint address(bind_ip_address, 0);
183 188
184 if (!CheckResult("Bind", socket_->Bind(address))) 189 if (!CheckResult("Bind", socket_->Bind(address)))
185 return false; 190 return false;
186 191
192 recv_buffer_ = new IOBufferWithSize(kDialRecvBufferSize);
193 if (!ReadSocket())
194 return false;
195 SendOneRequest();
196 return true;
197 }
198
199 void DialServiceImpl::SendOneRequest() {
200 if (num_requests_sent_ == max_requests_) {
201 request_timer_.Stop();
202 return;
203 }
204 num_requests_sent_++;
187 if (!socket_.get()) { 205 if (!socket_.get()) {
188 DLOG(WARNING) << "Socket not connected."; 206 DLOG(WARNING) << "Socket not connected.";
189 return false; 207 return;
190 } 208 }
191
192 recv_buffer_ = new IOBufferWithSize(kDialRecvBufferSize);
193 ReadSocket();
194
195 if (is_writing_) { 209 if (is_writing_) {
196 DVLOG(1) << "Already writing."; 210 DVLOG(1) << "Already writing.";
197 return false; 211 return;
198 } 212 }
213 DVLOG(1) << "Sending request " << num_requests_sent_ << "/"
214 << max_requests_;
199 is_writing_ = true; 215 is_writing_ = true;
200 int result = socket_->SendTo( 216 int result = socket_->SendTo(
201 send_buffer_.get(), 217 send_buffer_.get(),
202 send_buffer_->size(), send_address_, 218 send_buffer_->size(), send_address_,
203 base::Bind(&DialServiceImpl::OnSocketWrite, this)); 219 base::Bind(&DialServiceImpl::OnSocketWrite, this));
204 bool result_ok = CheckResult("SendTo", result); 220 bool result_ok = CheckResult("SendTo", result);
205 if (result_ok && result > 0) { 221 if (result_ok && result > 0) {
206 // Synchronous write. 222 // Synchronous write.
207 OnSocketWrite(result); 223 OnSocketWrite(result);
208 } 224 }
209 return result_ok; 225 return;
justinlin 2013/02/08 08:56:20 Don't need this return
mark a. foltz 2013/02/08 22:07:58 Done.
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 } 226 }
225 227
226 void DialServiceImpl::OnSocketWrite(int result) { 228 void DialServiceImpl::OnSocketWrite(int result) {
227 DCHECK(thread_checker_.CalledOnValidThread()); 229 DCHECK(thread_checker_.CalledOnValidThread());
228 is_writing_ = false; 230 is_writing_ = false;
229 if (!CheckResult("OnSocketWrite", result)) 231 if (!CheckResult("OnSocketWrite", result))
230 return; 232 return;
231
232 if (result != send_buffer_->size()) { 233 if (result != send_buffer_->size()) {
233 DLOG(ERROR) << "Sent " << result << " chars, expected " 234 DLOG(ERROR) << "Sent " << result << " chars, expected "
234 << send_buffer_->size() << " chars"; 235 << send_buffer_->size() << " chars";
235 } 236 }
236 // If discovery is inactive, no reason to notify observers. 237 // If discovery is inactive, no reason to notify observers.
237 if (!discovery_active_) { 238 if (!discovery_active_) {
238 DVLOG(1) << "Request sent after discovery finished. Ignoring."; 239 DVLOG(1) << "Request sent after discovery finished. Ignoring.";
239 return; 240 return;
240 } 241 }
241 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this)); 242 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this));
242 num_requests_sent_++; 243 // If we need to send additional requests, schedule a timer to do so.
244 if (num_requests_sent_ < max_requests_ && num_requests_sent_ == 1) {
245 request_timer_.Start(FROM_HERE,
246 request_interval_,
247 this,
248 &DialServiceImpl::SendOneRequest);
249 }
243 } 250 }
244 251
245 bool DialServiceImpl::ReadSocket() { 252 bool DialServiceImpl::ReadSocket() {
246 DCHECK(thread_checker_.CalledOnValidThread()); 253 DCHECK(thread_checker_.CalledOnValidThread());
247 if (!socket_.get()) { 254 if (!socket_.get()) {
248 DLOG(WARNING) << "Socket not connected."; 255 DLOG(WARNING) << "Socket not connected.";
249 return false; 256 return false;
250 } 257 }
251 258
252 if (is_reading_) { 259 if (is_reading_) {
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 } else { 370 } else {
364 DVLOG(1) << "Malformed or missing " << kSsdpConfigIdHeader << ": " 371 DVLOG(1) << "Malformed or missing " << kSsdpConfigIdHeader << ": "
365 << config_id; 372 << config_id;
366 } 373 }
367 374
368 return true; 375 return true;
369 } 376 }
370 377
371 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) { 378 void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) {
372 DCHECK(thread_checker_.CalledOnValidThread()); 379 DCHECK(thread_checker_.CalledOnValidThread());
373 if (!networks.size()) {
374 DVLOG(1) << "No network interfaces found!";
375 return;
376 }
377
378 const NetworkInterface* interface = NULL; 380 const NetworkInterface* interface = NULL;
379 // Returns the first IPv4 address found. If there is a need for discovery 381 // Returns the first IPv4 address found. If there is a need for discovery
380 // across multiple networks, we could manage multiple sockets. 382 // across multiple networks, we could manage multiple sockets.
381 383
382 // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286 384 // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286
383 for (NetworkInterfaceList::const_iterator iter = networks.begin(); 385 for (NetworkInterfaceList::const_iterator iter = networks.begin();
384 iter != networks.end(); ++iter) { 386 iter != networks.end(); ++iter) {
385 DVLOG(1) << "Found " << iter->name << ", " 387 DVLOG(1) << "Found " << iter->name << ", "
386 << net::IPAddressToString(iter->address); 388 << net::IPAddressToString(iter->address);
387 if (iter->address.size() == net::kIPv4AddressSize) { 389 if (iter->address.size() == net::kIPv4AddressSize) {
388 interface = &*iter; 390 interface = &*iter;
389 break; 391 break;
390 } 392 }
391 } 393 }
392 394
393 if (interface == NULL) { 395 if (interface == NULL) {
394 DVLOG(1) << "Could not find a valid interface to bind."; 396 DVLOG(1) << "Could not find a valid interface to bind.";
397 FinishDiscovery();
395 } else { 398 } else {
396 BindAndWriteSocket(*interface); 399 BindSocketAndSendRequest(interface->address);
397 } 400 }
398 } 401 }
399 402
400 void DialServiceImpl::DoGetNetworkList() { 403 void DialServiceImpl::DoGetNetworkList() {
401 NetworkInterfaceList list; 404 NetworkInterfaceList list;
402 bool success = net::GetNetworkList(&list); 405 bool success = net::GetNetworkList(&list);
403 if (!success) { 406 if (!success) {
404 DVLOG(1) << "Could not retrieve network list!"; 407 DVLOG(1) << "Could not retrieve network list!";
405 } 408 }
406 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( 409 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
407 &DialServiceImpl::SendNetworkList, this, list)); 410 &DialServiceImpl::SendNetworkList, this, list));
408 } 411 }
409 412
413 void DialServiceImpl::FinishDiscovery() {
414 DCHECK(thread_checker_.CalledOnValidThread());
415 DCHECK(discovery_active_);
416 DVLOG(1) << "Discovery finished.";
417 CloseSocket();
418 finish_timer_.Stop();
419 request_timer_.Stop();
420 discovery_active_ = false;
421 num_requests_sent_ = 0;
422 FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this));
justinlin 2013/02/08 08:56:20 Don't need to do this in the CL, but I kinda feel
mark a. foltz 2013/02/08 22:07:58 I agree with you that DialService is exclusively f
423 }
424
410 void DialServiceImpl::CloseSocket() { 425 void DialServiceImpl::CloseSocket() {
411 DCHECK(thread_checker_.CalledOnValidThread()); 426 DCHECK(thread_checker_.CalledOnValidThread());
412 is_reading_ = false; 427 is_reading_ = false;
413 is_writing_ = false; 428 is_writing_ = false;
414 if (!socket_.get()) 429 if (!socket_.get())
415 return; 430 return;
416 socket_.reset(); 431 socket_.reset();
417 } 432 }
418 433
419 bool DialServiceImpl::CheckResult(const char* operation, int result) { 434 bool DialServiceImpl::CheckResult(const char* operation, int result) {
420 DCHECK(thread_checker_.CalledOnValidThread()); 435 DCHECK(thread_checker_.CalledOnValidThread());
421 DVLOG(1) << "Operation " << operation << " result " << result; 436 DVLOG(1) << "Operation " << operation << " result " << result;
422 if (result < net::OK && result != net::ERR_IO_PENDING) { 437 if (result < net::OK && result != net::ERR_IO_PENDING) {
423 CloseSocket(); 438 CloseSocket();
424 std::string error_str(net::ErrorToString(result)); 439 std::string error_str(net::ErrorToString(result));
425 DVLOG(0) << "dial socket error: " << error_str; 440 DVLOG(0) << "dial socket error: " << error_str;
426 FOR_EACH_OBSERVER(Observer, observer_list_, OnError(this, error_str)); 441 FOR_EACH_OBSERVER(Observer, observer_list_, OnError(this, error_str));
427 return false; 442 return false;
428 } 443 }
429 return true; 444 return true;
430 } 445 }
431 446
432 } // namespace extensions 447 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698