12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/dial/dial_service.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <set> 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <utility> 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 165e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/dial/dial_device_data.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_version_info.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/completion_callback.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/ip_endpoint.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_errors.h" 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_util.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/http/http_response_headers.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/http/http_util.h" 287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h" 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_CHROMEOS) 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chromeos/network/network_state.h" 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chromeos/network/network_state_handler.h" 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "third_party/cros_system_api/dbus/service_constants.h" 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::Time; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::TimeDelta; 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::HttpResponseHeaders; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::HttpUtil; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::IOBufferWithSize; 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::IPAddressNumber; 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::IPEndPoint; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::NetworkInterface; 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::NetworkInterfaceList; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::StringIOBuffer; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using net::UDPSocket; 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions { 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The total number of requests to make per discovery cycle. 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDialMaxRequests = 4; 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The interval to wait between successive requests. 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDialRequestIntervalMillis = 1000; 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The maximum delay a device may wait before responding (MX). 59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kDialMaxResponseDelaySecs = 1; 60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The maximum time a response is expected after a M-SEARCH request. 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDialResponseTimeoutSecs = 2; 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The multicast IP address for discovery. 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDialRequestAddress[] = "239.255.255.250"; 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The UDP port number for discovery. 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDialRequestPort = 1900; 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The DIAL service type as part of the search request. 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kDialSearchType[] = "urn:dial-multiscreen-org:service:dial:1"; 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// SSDP headers parsed from the response. 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kSsdpLocationHeader[] = "LOCATION"; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kSsdpCacheControlHeader[] = "CACHE-CONTROL"; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kSsdpConfigIdHeader[] = "CONFIGID.UPNP.ORG"; 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kSsdpUsnHeader[] = "USN"; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The receive buffer size, in bytes. 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDialRecvBufferSize = 1500; 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Gets a specific header from |headers| and puts it in |value|. 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GetHeader(HttpResponseHeaders* headers, const char* name, 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* value) { 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return headers->EnumerateHeader(NULL, std::string(name), value); 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns the request string. 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string BuildRequest() { 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Extra line at the end to make UPnP lib happy. 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome::VersionInfo version; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string request(base::StringPrintf( 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "M-SEARCH * HTTP/1.1\r\n" 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HOST: %s:%i\r\n" 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "MAN: \"ssdp:discover\"\r\n" 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "MX: %d\r\n" 97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ST: %s\r\n" 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "USER-AGENT: %s/%s %s\r\n" 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "\r\n", 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kDialRequestAddress, 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kDialRequestPort, 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kDialMaxResponseDelaySecs, 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kDialSearchType, 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) version.Name().c_str(), 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) version.Version().c_str(), 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) version.OSType().c_str())); 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1500 is a good MTU value for most Ethernet LANs. 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(request.size() <= 1500); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return request; 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if !defined(OS_CHROMEOS) 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void GetNetworkListOnFileThread( 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const scoped_refptr<base::MessageLoopProxy>& loop, 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const base::Callback<void(const NetworkInterfaceList& networks)>& cb) { 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) NetworkInterfaceList list; 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool success = net::GetNetworkList( 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &list, net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES); 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!success) 120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Could not retrieve network list!"; 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) loop->PostTask(FROM_HERE, base::Bind(cb, list)); 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#else 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Finds the IP address of the preferred interface of network type |type| 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// to bind the socket and inserts the address into |bind_address_list|. This 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// ChromeOS version can prioritize wifi and ethernet interfaces. 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InsertBestBindAddressChromeOS( 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const chromeos::NetworkTypePattern& type, 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<IPAddressNumber>* bind_address_list) { 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const chromeos::NetworkState* state = chromeos::NetworkHandler::Get() 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ->network_state_handler()->ConnectedNetworkByType(type); 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) IPAddressNumber bind_ip_address; 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (state 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) && net::ParseIPLiteralToNumber(state->ip_address(), &bind_ip_address) 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) && bind_ip_address.size() == net::kIPv4AddressSize) { 139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(2) << "Found " << state->type() << ", " << state->name() << ": " 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << state->ip_address(); 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bind_address_list->push_back(bind_ip_address); 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif // !defined(OS_CHROMEOS) 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DialServiceImpl::DialSocket::DialSocket( 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Closure& discovery_request_cb, 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Callback<void(const DialDeviceData&)>& device_discovered_cb, 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Closure& on_error_cb) 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : discovery_request_cb_(discovery_request_cb), 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device_discovered_cb_(device_discovered_cb), 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) on_error_cb_(on_error_cb), 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_writing_(false), 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_reading_(false) { 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DialServiceImpl::DialSocket::~DialSocket() { 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DialServiceImpl::DialSocket::CreateAndBindSocket( 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const IPAddressNumber& bind_ip_address, 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::NetLog* net_log, 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::NetLog::Source net_log_source) { 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!socket_.get()); 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(bind_ip_address.size() == net::kIPv4AddressSize); 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::RandIntCallback rand_cb = base::Bind(&base::RandInt); 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_.reset(new UDPSocket(net::DatagramSocket::RANDOM_BIND, 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rand_cb, 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net_log, 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net_log_source)); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_->AllowBroadcast(); 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 0 means bind a random port 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) IPEndPoint address(bind_ip_address, 0); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!CheckResult("Bind", socket_->Bind(address))) 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(socket_.get()); 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) recv_buffer_ = new IOBufferWithSize(kDialRecvBufferSize); 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return ReadSocket(); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::DialSocket::SendOneRequest( 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const net::IPEndPoint& send_address, 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const scoped_refptr<net::StringIOBuffer>& send_buffer) { 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!socket_.get()) { 194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Socket not connected."; 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_writing_) { 199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Already writing."; 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_writing_ = true; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int result = socket_->SendTo( 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) send_buffer.get(), send_buffer->size(), send_address, 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&DialServiceImpl::DialSocket::OnSocketWrite, 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this), 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) send_buffer->size())); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool result_ok = CheckResult("SendTo", result); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result_ok && result > 0) { 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Synchronous write. 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnSocketWrite(send_buffer->size(), result); 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DialServiceImpl::DialSocket::IsClosed() { 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return !socket_.get(); 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DialServiceImpl::DialSocket::CheckResult(const char* operation, 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int result) { 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Operation " << operation << " result " << result; 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (result < net::OK && result != net::ERR_IO_PENDING) { 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Close(); 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string error_str(net::ErrorToString(result)); 228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "dial socket error: " << error_str; 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) on_error_cb_.Run(); 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::DialSocket::Close() { 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_reading_ = false; 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_writing_ = false; 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) socket_.reset(); 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::DialSocket::OnSocketWrite(int send_buffer_size, 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int result) { 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_writing_ = false; 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!CheckResult("OnSocketWrite", result)) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (result != send_buffer_size) { 249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Sent " << result << " chars, expected " 250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << send_buffer_size << " chars"; 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) discovery_request_cb_.Run(); 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DialServiceImpl::DialSocket::ReadSocket() { 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!socket_.get()) { 258116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Socket not connected."; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_reading_) { 263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Already reading."; 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int result = net::OK; 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool result_ok = true; 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) do { 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_reading_ = true; 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result = socket_->RecvFrom( 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) recv_buffer_.get(), 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) kDialRecvBufferSize, &recv_address_, 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&DialServiceImpl::DialSocket::OnSocketRead, 2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this))); 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result_ok = CheckResult("RecvFrom", result); 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result != net::ERR_IO_PENDING) 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_reading_ = false; 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result_ok && result > 0) { 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Synchronous read. 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleResponse(result); 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } while (result_ok && result != net::OK && result != net::ERR_IO_PENDING); 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return result_ok; 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::DialSocket::OnSocketRead(int result) { 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_reading_ = false; 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!CheckResult("OnSocketRead", result)) 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result > 0) 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HandleResponse(result); 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Await next response. 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ReadSocket(); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::DialSocket::HandleResponse(int bytes_read) { 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GT(bytes_read, 0); 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bytes_read > kDialRecvBufferSize) { 303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << bytes_read << " > " << kDialRecvBufferSize << "!?"; 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) VLOG(2) << "Read " << bytes_read << " bytes from " 3070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) << recv_address_.ToString(); 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string response(recv_buffer_->data(), bytes_read); 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Time response_time = Time::Now(); 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Attempt to parse response, notify observers if successful. 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DialDeviceData parsed_device; 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ParseResponse(response, response_time, &parsed_device)) 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device_discovered_cb_.Run(parsed_device); 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DialServiceImpl::DialSocket::ParseResponse( 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& response, 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Time& response_time, 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DialDeviceData* device) { 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int headers_end = HttpUtil::LocateEndOfHeaders(response.c_str(), 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) response.size()); 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (headers_end < 1) { 326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Headers invalid or empty, ignoring: " << response; 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string raw_headers = 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HttpUtil::AssembleRawHeaders(response.c_str(), headers_end); 331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(3) << "raw_headers: " << raw_headers << "\n"; 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<HttpResponseHeaders> headers = 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new HttpResponseHeaders(raw_headers); 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string device_url_str; 336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!GetHeader(headers.get(), kSsdpLocationHeader, &device_url_str) || 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) device_url_str.empty()) { 338116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "No LOCATION header found."; 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL device_url(device_url_str); 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!DialDeviceData::IsDeviceDescriptionUrl(device_url)) { 344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "URL " << device_url_str << " not valid."; 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string device_id; 349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!GetHeader(headers.get(), kSsdpUsnHeader, &device_id) || 350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) device_id.empty()) { 351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "No USN header found."; 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) device->set_device_id(device_id); 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) device->set_device_description_url(device_url); 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) device->set_response_time(response_time); 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(mfoltz): Parse the max-age value from the cache control header. 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // http://crbug.com/165289 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string cache_control; 362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) GetHeader(headers.get(), kSsdpCacheControlHeader, &cache_control); 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string config_id; 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int config_id_int; 366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (GetHeader(headers.get(), kSsdpConfigIdHeader, &config_id) && 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringToInt(config_id, &config_id_int)) { 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) device->set_config_id(config_id_int); 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 370116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Malformed or missing " << kSsdpConfigIdHeader << ": " 3710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) << config_id; 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DialServiceImpl::DialServiceImpl(net::NetLog* net_log) 3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : discovery_active_(false), 3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) num_requests_sent_(0), 3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) max_requests_(kDialMaxRequests), 3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finish_delay_(TimeDelta::FromMilliseconds((kDialMaxRequests - 1) * 3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kDialRequestIntervalMillis) + 3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) TimeDelta::FromSeconds(kDialResponseTimeoutSecs)), 3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_interval_( 3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) TimeDelta::FromMilliseconds(kDialRequestIntervalMillis)) { 3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IPAddressNumber address; 3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool success = net::ParseIPLiteralToNumber(kDialRequestAddress, &address); 3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(success); 3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) send_address_ = IPEndPoint(address, kDialRequestPort); 3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) send_buffer_ = new StringIOBuffer(BuildRequest()); 3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net_log_ = net_log; 3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net_log_source_.type = net::NetLog::SOURCE_UDP_SOCKET; 3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net_log_source_.id = net_log_->NextID(); 3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DialServiceImpl::~DialServiceImpl() { 3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::AddObserver(Observer* observer) { 4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) observer_list_.AddObserver(observer); 4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::RemoveObserver(Observer* observer) { 4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) observer_list_.RemoveObserver(observer); 4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DialServiceImpl::HasObserver(Observer* observer) { 4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return observer_list_.HasObserver(observer); 4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DialServiceImpl::Discover() { 4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (discovery_active_) { 4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Discovery is already active - returning."; 4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) discovery_active_ = true; 4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Discovery started."; 4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StartDiscovery(); 4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::StartDiscovery() { 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(discovery_active_); 4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (HasOpenSockets()) { 4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Calling StartDiscovery() with open sockets. Returning."; 4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS) 4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The ChromeOS specific version of getting network interfaces does not 4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // require trampolining to another thread, and contains additional interface 4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // information such as interface types (i.e. wifi vs cellular). 4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<IPAddressNumber> chrome_os_address_list; 4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) InsertBestBindAddressChromeOS(chromeos::NetworkTypePattern::Ethernet(), 4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &chrome_os_address_list); 4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) InsertBestBindAddressChromeOS(chromeos::NetworkTypePattern::WiFi(), 4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &chrome_os_address_list); 4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DiscoverOnAddresses(chrome_os_address_list); 4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else 4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( 4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &GetNetworkListOnFileThread, 4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::MessageLoopProxy::current(), base::Bind( 4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &DialServiceImpl::SendNetworkList, AsWeakPtr()))); 4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif 4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DialServiceImpl::SendNetworkList(const NetworkInterfaceList& networks) { 457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) typedef std::pair<uint32, net::AddressFamily> InterfaceIndexAddressFamily; 4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::set<InterfaceIndexAddressFamily> interface_index_addr_family_seen; 4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<IPAddressNumber> ip_addresses; 461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Binds a socket to each IPv4 network interface found. Note that 4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // there may be duplicates in |networks|, so address family + interface index 4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // is used to identify unique interfaces. 465f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(mfoltz): Support IPV6 multicast. http://crbug.com/165286 466f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (NetworkInterfaceList::const_iterator iter = networks.begin(); 467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) iter != networks.end(); ++iter) { 4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::AddressFamily addr_family = net::GetAddressFamily(iter->address); 469116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(2) << "Found " << iter->name << ", " 470116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << net::IPAddressToString(iter->address) 471116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << ", address family: " << addr_family; 4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (addr_family == net::ADDRESS_FAMILY_IPV4) { 4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) InterfaceIndexAddressFamily interface_index_addr_family = 4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::make_pair(iter->interface_index, addr_family); 4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool inserted = interface_index_addr_family_seen 4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) .insert(interface_index_addr_family) 4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) .second; 4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We have not seen this interface before, so add its IP address to the 4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // discovery list. 4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (inserted) { 4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Encountered " 4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << "interface index: " << iter->interface_index << ", " 4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << "address family: " << addr_family << " for the first time, " 4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << "adding IP address " << net::IPAddressToString(iter->address) 4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << " to list."; 4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ip_addresses.push_back(iter->address); 4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Already encountered " 4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << "interface index: " << iter->interface_index << ", " 4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << "address family: " << addr_family << " before, not adding."; 4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 493f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DiscoverOnAddresses(ip_addresses); 4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::DiscoverOnAddresses( 4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::vector<IPAddressNumber>& ip_addresses) { 5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ip_addresses.empty()) { 501116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "Could not find a valid interface to bind. Finishing discovery"; 5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FinishDiscovery(); 5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Schedule a timer to finish the discovery process (and close the sockets). 5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (finish_delay_ > TimeDelta::FromSeconds(0)) { 5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Starting timer to finish discovery."; 5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finish_timer_.Start(FROM_HERE, 5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finish_delay_, 5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this, 5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &DialServiceImpl::FinishDiscovery); 5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (std::vector<IPAddressNumber>::const_iterator iter = ip_addresses.begin(); 5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) iter != ip_addresses.end(); 5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++iter) 5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BindAndAddSocket(*iter); 5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SendOneRequest(); 5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::BindAndAddSocket(const IPAddressNumber& bind_ip_address) { 5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<DialServiceImpl::DialSocket> dial_socket(CreateDialSocket()); 5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (dial_socket->CreateAndBindSocket(bind_ip_address, net_log_, 5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net_log_source_)) 5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dial_sockets_.push_back(dial_socket.release()); 5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<DialServiceImpl::DialSocket> DialServiceImpl::CreateDialSocket() { 5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<DialServiceImpl::DialSocket> dial_socket( 5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new DialServiceImpl::DialSocket( 5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&DialServiceImpl::NotifyOnDiscoveryRequest, AsWeakPtr()), 5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&DialServiceImpl::NotifyOnDeviceDiscovered, AsWeakPtr()), 5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&DialServiceImpl::NotifyOnError, AsWeakPtr()))); 5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return dial_socket.Pass(); 5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::SendOneRequest() { 5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (num_requests_sent_ == max_requests_) { 5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Reached max requests; stopping request timer."; 5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_timer_.Stop(); 5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) num_requests_sent_++; 5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Sending request " << num_requests_sent_ << "/" 5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << max_requests_; 5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (ScopedVector<DialServiceImpl::DialSocket>::iterator iter = 5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dial_sockets_.begin(); 5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) iter != dial_sockets_.end(); 5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++iter) { 5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!((*iter)->IsClosed())) 5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) (*iter)->SendOneRequest(send_address_, send_buffer_); 5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::NotifyOnDiscoveryRequest() { 5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If discovery is inactive, no reason to notify observers. 5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!discovery_active_) { 5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Request sent after discovery finished. Ignoring."; 5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Notifying observers of discovery request"; 5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this)); 5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If we need to send additional requests, schedule a timer to do so. 5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (num_requests_sent_ < max_requests_ && num_requests_sent_ == 1) { 5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Scheduling timer to send additional requests"; 5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // TODO(imcheng): Move this to SendOneRequest() once the implications are 5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // understood. 5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_timer_.Start(FROM_HERE, 5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_interval_, 5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this, 5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &DialServiceImpl::SendOneRequest); 5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::NotifyOnDeviceDiscovered( 5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const DialDeviceData& device_data) { 5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!discovery_active_) { 5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(2) << "Got response after discovery finished. Ignoring."; 5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FOR_EACH_OBSERVER(Observer, observer_list_, 5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnDeviceDiscovered(this, device_data)); 5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DialServiceImpl::NotifyOnError() { 5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // TODO(imcheng): Modify upstream so that the device list is not cleared 5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // when it could still potentially discover devices on other sockets. 5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FOR_EACH_OBSERVER(Observer, observer_list_, 5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnError(this, 5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HasOpenSockets() ? DIAL_SERVICE_SOCKET_ERROR 5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : DIAL_SERVICE_NO_INTERFACES)); 599f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 600f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DialServiceImpl::FinishDiscovery() { 6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(discovery_active_); 6040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) VLOG(2) << "Discovery finished."; 6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Close all open sockets. 6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) dial_sockets_.clear(); 6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) finish_timer_.Stop(); 6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_timer_.Stop(); 6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) discovery_active_ = false; 6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_requests_sent_ = 0; 6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this)); 6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DialServiceImpl::HasOpenSockets() { 6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (ScopedVector<DialSocket>::const_iterator iter = dial_sockets_.begin(); 6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) iter != dial_sockets_.end(); 6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++iter) { 6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!((*iter)->IsClosed())) 6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace extensions 625