15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "device/test/usb_test_gadget.h"
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <string>
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <vector>
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/command_line.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/compiler_specific.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/files/file.h"
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/files/file_path.h"
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/macros.h"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/memory/ref_counted.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/path_service.h"
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/process/process.h"
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/run_loop.h"
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/stringprintf.h"
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/threading/platform_thread.h"
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/time/time.h"
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/usb/usb_device.h"
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/usb/usb_device_handle.h"
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/usb/usb_service.h"
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/proxy/proxy_service.h"
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/url_request/url_fetcher.h"
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h"
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/url_request/url_request_context.h"
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/url_request/url_request_context_builder.h"
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "url/gurl.h"
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)using ::base::PlatformThread;
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)using ::base::TimeDelta;
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace device {
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace {
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const char kCommandLineSwitch[] = "enable-gadget-tests";
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kClaimRetries = 100;  // 5 seconds
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kDisconnectRetries = 100;  // 5 seconds
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kRetryPeriod = 50;  // 0.05 seconds
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kReconnectRetries = 100;  // 5 seconds
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kUpdateRetries = 100;  // 5 seconds
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)struct UsbTestGadgetConfiguration {
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UsbTestGadget::Type type;
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char* http_resource;
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  uint16 product_id;
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const struct UsbTestGadgetConfiguration kConfigurations[] = {
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    {UsbTestGadget::DEFAULT, "/unconfigure", 0x58F0},
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    {UsbTestGadget::KEYBOARD, "/keyboard/configure", 0x58F1},
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    {UsbTestGadget::MOUSE, "/mouse/configure", 0x58F2},
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    {UsbTestGadget::HID_ECHO, "/hid_echo/configure", 0x58F3},
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    {UsbTestGadget::ECHO, "/echo/configure", 0x58F4},
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class UsbTestGadgetImpl : public UsbTestGadget {
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public:
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual ~UsbTestGadgetImpl();
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual bool Unclaim() OVERRIDE;
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual bool Disconnect() OVERRIDE;
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual bool Reconnect() OVERRIDE;
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual bool SetType(Type type) OVERRIDE;
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual UsbDevice* GetDevice() const OVERRIDE;
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual std::string GetSerialNumber() const OVERRIDE;
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) protected:
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UsbTestGadgetImpl();
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private:
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<net::URLFetcher> CreateURLFetcher(
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const GURL& url,
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      net::URLFetcher::RequestType request_type,
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      net::URLFetcherDelegate* delegate);
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int SimplePOSTRequest(const GURL& url, const std::string& form_data);
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool FindUnclaimed();
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool GetVersion(std::string* version);
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool Update();
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool FindClaimed();
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool ReadLocalVersion(std::string* version);
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool ReadLocalPackage(std::string* package);
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool ReadFile(const base::FilePath& file_path, std::string* content);
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  class Delegate : public net::URLFetcherDelegate {
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   public:
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Delegate() {}
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    virtual ~Delegate() {}
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    void WaitForCompletion() {
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      run_loop_.Run();
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      run_loop_.Quit();
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   private:
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::RunLoop run_loop_;
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(Delegate);
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  };
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_refptr<UsbDevice> device_;
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string device_address_;
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<net::URLRequestContext> request_context_;
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string session_id_;
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UsbService* usb_service_;
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  friend class UsbTestGadget;
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(UsbTestGadgetImpl);
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadget::IsTestEnabled() {
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::CommandLine* command_line = CommandLine::ForCurrentProcess();
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return command_line->HasSwitch(kCommandLineSwitch);
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)scoped_ptr<UsbTestGadget> UsbTestGadget::Claim() {
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<UsbTestGadgetImpl> gadget(new UsbTestGadgetImpl);
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int retries = kClaimRetries;
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (!gadget->FindUnclaimed()) {
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (--retries == 0) {
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LOG(ERROR) << "Failed to find an unclaimed device.";
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return scoped_ptr<UsbTestGadget>();
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PlatformThread::Sleep(TimeDelta::FromMilliseconds(kRetryPeriod));
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "It took " << (kClaimRetries - retries)
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << " retries to find an unclaimed device.";
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return gadget.PassAs<UsbTestGadget>();
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)UsbTestGadgetImpl::UsbTestGadgetImpl() {
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  net::URLRequestContextBuilder context_builder;
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  context_builder.set_proxy_service(net::ProxyService::CreateDirect());
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  request_context_.reset(context_builder.Build());
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::ProcessId process_id = base::Process::Current().pid();
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  session_id_ = base::StringPrintf(
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "%s:%p", base::HexEncode(&process_id, sizeof(process_id)).c_str(), this);
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  usb_service_ = UsbService::GetInstance(NULL);
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)UsbTestGadgetImpl::~UsbTestGadgetImpl() {
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!device_address_.empty()) {
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Unclaim();
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)UsbDevice* UsbTestGadgetImpl::GetDevice() const {
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return device_.get();
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistd::string UsbTestGadgetImpl::GetSerialNumber() const {
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return device_address_;
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)scoped_ptr<net::URLFetcher> UsbTestGadgetImpl::CreateURLFetcher(
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const GURL& url, net::URLFetcher::RequestType request_type,
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    net::URLFetcherDelegate* delegate) {
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<net::URLFetcher> url_fetcher(
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      net::URLFetcher::Create(url, request_type, delegate));
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  url_fetcher->SetRequestContext(
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new net::TrivialURLRequestContextGetter(
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          request_context_.get(),
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          base::MessageLoop::current()->message_loop_proxy()));
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return url_fetcher.PassAs<net::URLFetcher>();
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int UsbTestGadgetImpl::SimplePOSTRequest(const GURL& url,
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                         const std::string& form_data) {
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Delegate delegate;
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<net::URLFetcher> url_fetcher =
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CreateURLFetcher(url, net::URLFetcher::POST, &delegate);
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  url_fetcher->SetUploadData("application/x-www-form-urlencoded", form_data);
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  url_fetcher->Start();
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate.WaitForCompletion();
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return url_fetcher->GetResponseCode();
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::FindUnclaimed() {
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<scoped_refptr<UsbDevice> > devices;
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  usb_service_->GetDevices(&devices);
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (std::vector<scoped_refptr<UsbDevice> >::const_iterator iter =
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         devices.begin(); iter != devices.end(); ++iter) {
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const scoped_refptr<UsbDevice> &device = *iter;
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (device->vendor_id() == 0x18D1 && device->product_id() == 0x58F0) {
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::string16 serial_utf16;
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (!device->GetSerialNumber(&serial_utf16)) {
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        continue;
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const std::string serial = base::UTF16ToUTF8(serial_utf16);
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const GURL url("http://" + serial + "/claim");
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const std::string form_data = base::StringPrintf(
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          "session_id=%s",
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          net::EscapeUrlEncodedData(session_id_, true).c_str());
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const int response_code = SimplePOSTRequest(url, form_data);
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (response_code == 200) {
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        device_address_ = serial;
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        device_ = device;
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break;
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // The device is probably claimed by another process.
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (response_code != 403) {
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        LOG(WARNING) << "Unexpected HTTP " << response_code << " from /claim.";
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string local_version;
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string version;
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!ReadLocalVersion(&local_version) ||
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      !GetVersion(&version)) {
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (version == local_version) {
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return true;
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return Update();
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::GetVersion(std::string* version) {
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Delegate delegate;
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const GURL url("http://" + device_address_ + "/version");
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<net::URLFetcher> url_fetcher =
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CreateURLFetcher(url, net::URLFetcher::GET, &delegate);
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  url_fetcher->Start();
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate.WaitForCompletion();
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int response_code = url_fetcher->GetResponseCode();
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (response_code != 200) {
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    VLOG(2) << "Unexpected HTTP " << response_code << " from /version.";
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  STLClearObject(version);
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!url_fetcher->GetResponseAsString(version)) {
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    VLOG(2) << "Failed to read body from /version.";
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::Update() {
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string version;
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!ReadLocalVersion(&version)) {
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  LOG(INFO) << "Updating " << device_address_ << " to " << version << "...";
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Delegate delegate;
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const GURL url("http://" + device_address_ + "/update");
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<net::URLFetcher> url_fetcher =
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CreateURLFetcher(url, net::URLFetcher::POST, &delegate);
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const std::string mime_header =
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::StringPrintf(
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "--foo\r\n"
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "Content-Disposition: form-data; name=\"file\"; "
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          "filename=\"usb_gadget-%s.zip\"\r\n"
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "Content-Type: application/octet-stream\r\n"
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "\r\n", version.c_str());
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const std::string mime_footer("\r\n--foo--\r\n");
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string package;
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!ReadLocalPackage(&package)) {
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  url_fetcher->SetUploadData("multipart/form-data; boundary=foo",
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                             mime_header + package + mime_footer);
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  url_fetcher->Start();
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  delegate.WaitForCompletion();
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int response_code = url_fetcher->GetResponseCode();
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (response_code != 200) {
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Unexpected HTTP " << response_code << " from /update.";
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int retries = kUpdateRetries;
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string new_version;
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (!GetVersion(&new_version) || new_version != version) {
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (--retries == 0) {
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LOG(ERROR) << "Device not responding with new version.";
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PlatformThread::Sleep(TimeDelta::FromMilliseconds(kRetryPeriod));
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "It took " << (kUpdateRetries - retries)
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << " retries to see the new version.";
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Release the old reference to the device and try to open a new one.
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_ = NULL;
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  retries = kReconnectRetries;
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (!FindClaimed()) {
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (--retries == 0) {
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LOG(ERROR) << "Failed to find updated device.";
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PlatformThread::Sleep(TimeDelta::FromMilliseconds(kRetryPeriod));
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "It took " << (kReconnectRetries - retries)
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << " retries to find the updated device.";
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::FindClaimed() {
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(!device_.get());
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string expected_serial = GetSerialNumber();
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<scoped_refptr<UsbDevice> > devices;
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  usb_service_->GetDevices(&devices);
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (std::vector<scoped_refptr<UsbDevice> >::iterator iter =
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         devices.begin(); iter != devices.end(); ++iter) {
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scoped_refptr<UsbDevice> &device = *iter;
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (device->vendor_id() == 0x18D1) {
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const uint16 product_id = device->product_id();
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      bool found = false;
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      for (size_t i = 0; i < arraysize(kConfigurations); ++i) {
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (product_id == kConfigurations[i].product_id) {
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          found = true;
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          break;
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!found) {
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        continue;
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::string16 serial_utf16;
3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (!device->GetSerialNumber(&serial_utf16)) {
3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        continue;
3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      std::string serial = base::UTF16ToUTF8(serial_utf16);
3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (serial != expected_serial) {
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        continue;
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_ = device;
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return true;
3725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return false;
3765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::ReadLocalVersion(std::string* version) {
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::FilePath file_path;
3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(PathService::Get(base::DIR_EXE, &file_path));
3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  file_path = file_path.AppendASCII("usb_gadget.zip.md5");
3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return ReadFile(file_path, version);
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::ReadLocalPackage(std::string* package) {
3875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::FilePath file_path;
3885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(PathService::Get(base::DIR_EXE, &file_path));
3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  file_path = file_path.AppendASCII("usb_gadget.zip");
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return ReadFile(file_path, package);
3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::ReadFile(const base::FilePath& file_path,
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                 std::string* content) {
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!file.IsValid()) {
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Cannot open " << file_path.MaybeAsASCII() << ": "
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               << base::File::ErrorToString(file.error_details());
4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  STLClearObject(content);
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int rv;
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  do {
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    char buf[4096];
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    rv = file.ReadAtCurrentPos(buf, sizeof buf);
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (rv == -1) {
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LOG(ERROR) << "Cannot read " << file_path.MaybeAsASCII() << ": "
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 << base::File::ErrorToString(file.error_details());
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content->append(buf, rv);
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } while (rv > 0);
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::Unclaim() {
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "Releasing the device at " << device_address_ << ".";
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const GURL url("http://" + device_address_ + "/unclaim");
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int response_code = SimplePOSTRequest(url, "");
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (response_code != 200) {
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Unexpected HTTP " << response_code << " from /unclaim.";
4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::SetType(Type type) {
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const struct UsbTestGadgetConfiguration* config = NULL;
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < arraysize(kConfigurations); ++i) {
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (kConfigurations[i].type == type) {
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      config = &kConfigurations[i];
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(config);
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const GURL url("http://" + device_address_ + config->http_resource);
4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int response_code = SimplePOSTRequest(url, "");
4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (response_code != 200) {
4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Unexpected HTTP " << response_code
4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)               << " from " << config->http_resource << ".";
4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Release the old reference to the device and try to open a new one.
4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int retries = kReconnectRetries;
4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (true) {
4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_ = NULL;
4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (FindClaimed() && device_->product_id() == config->product_id) {
4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (--retries == 0) {
4585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LOG(ERROR) << "Failed to find updated device.";
4595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
4605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PlatformThread::Sleep(TimeDelta::FromMilliseconds(kRetryPeriod));
4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "It took " << (kReconnectRetries - retries)
4645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << " retries to find the updated device.";
4655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::Disconnect() {
4705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const GURL url("http://" + device_address_ + "/disconnect");
4715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int response_code = SimplePOSTRequest(url, "");
4725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (response_code != 200) {
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Unexpected HTTP " << response_code << " from /disconnect.";
4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Release the old reference to the device and wait until it can't be found.
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int retries = kDisconnectRetries;
4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (true) {
4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    device_ = NULL;
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (!FindClaimed()) {
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (--retries == 0) {
4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LOG(ERROR) << "Device did not disconnect.";
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PlatformThread::Sleep(TimeDelta::FromMilliseconds(kRetryPeriod));
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "It took " << (kDisconnectRetries - retries)
4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << " retries for the device to disconnect.";
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool UsbTestGadgetImpl::Reconnect() {
4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const GURL url("http://" + device_address_ + "/reconnect");
4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int response_code = SimplePOSTRequest(url, "");
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (response_code != 200) {
5025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LOG(ERROR) << "Unexpected HTTP " << response_code << " from /reconnect.";
5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
5045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int retries = kDisconnectRetries;
5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  while (true) {
5085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (FindClaimed()) {
5095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      break;
5105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
5115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (--retries == 0) {
5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      LOG(ERROR) << "Device did not reconnect.";
5135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
5145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
5155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PlatformThread::Sleep(TimeDelta::FromMilliseconds(kRetryPeriod));
5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "It took " << (kDisconnectRetries - retries)
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << " retries for the device to reconnect.";
5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return true;
5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
5225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace device
524