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