Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / music_manager_private / device_id_win.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
6
7 // Note: The order of header includes is important, as we want both pre-Vista
8 // and post-Vista data structures to be defined, specifically
9 // PIP_ADAPTER_ADDRESSES and PMIB_IF_ROW2.
10 #include <winsock2.h>
11 #include <ws2def.h>
12 #include <ws2ipdef.h>
13 #include <iphlpapi.h>
14
15 #include <string>
16
17 #include "base/files/file_path.h"
18 #include "base/logging.h"
19 #include "base/scoped_native_library.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "base/threading/thread_restrictions.h"
23 #include "base/win/windows_version.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "net/base/net_util.h"
26
27 #if defined(ENABLE_RLZ)
28 #include "rlz/lib/machine_id.h"
29 #endif
30
31 namespace {
32
33 using extensions::api::DeviceId;
34
35 typedef base::Callback<bool(const void* bytes, size_t size)>
36     IsValidMacAddressCallback;
37
38 class MacAddressProcessor {
39  public:
40   MacAddressProcessor(const IsValidMacAddressCallback& is_valid_mac_address)
41     : is_valid_mac_address_(is_valid_mac_address),
42       found_index_(ULONG_MAX) {
43   }
44
45   // Iterate through the interfaces, looking for the valid MAC address with the
46   // lowest IfIndex.
47   void ProcessAdapterAddress(PIP_ADAPTER_ADDRESSES address) {
48     if (address->IfType == IF_TYPE_TUNNEL)
49       return;
50
51     ProcessPhysicalAddress(address->IfIndex,
52                            address->PhysicalAddress,
53                            address->PhysicalAddressLength);
54   }
55
56   void ProcessInterfaceRow(const PMIB_IF_ROW2 row) {
57     if (row->Type == IF_TYPE_TUNNEL ||
58         !row->InterfaceAndOperStatusFlags.HardwareInterface) {
59       return;
60     }
61
62     ProcessPhysicalAddress(row->InterfaceIndex,
63                            row->PhysicalAddress,
64                            row->PhysicalAddressLength);
65   }
66
67   std::string mac_address() const { return found_mac_address_; }
68
69  private:
70   void ProcessPhysicalAddress(NET_IFINDEX index,
71                               const void* bytes,
72                               size_t size) {
73     if (index >= found_index_ || size == 0)
74       return;
75
76     if (!is_valid_mac_address_.Run(bytes, size))
77       return;
78
79     found_mac_address_ = base::StringToLowerASCII(base::HexEncode(bytes, size));
80     found_index_ = index;
81   }
82
83   const IsValidMacAddressCallback& is_valid_mac_address_;
84   std::string found_mac_address_;
85   NET_IFINDEX found_index_;
86 };
87
88 std::string GetMacAddressFromGetAdaptersAddresses(
89     const IsValidMacAddressCallback& is_valid_mac_address) {
90   base::ThreadRestrictions::AssertIOAllowed();
91
92   // MS recommends a default size of 15k.
93   ULONG bufferSize = 15 * 1024;
94   // Disable as much as we can, since all we want is MAC addresses.
95   ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER |
96                 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST |
97                 GAA_FLAG_SKIP_UNICAST;
98   std::vector<unsigned char> buffer(bufferSize);
99   PIP_ADAPTER_ADDRESSES adapterAddresses =
100       reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
101
102   DWORD result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
103                                       adapterAddresses, &bufferSize);
104   if (result == ERROR_BUFFER_OVERFLOW) {
105     buffer.resize(bufferSize);
106     adapterAddresses =
107         reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
108     result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
109                                   adapterAddresses, &bufferSize);
110   }
111
112   if (result != NO_ERROR) {
113     VLOG(ERROR) << "GetAdapatersAddresses failed with error " << result;
114     return "";
115   }
116
117   MacAddressProcessor processor(is_valid_mac_address);
118   for (; adapterAddresses != NULL; adapterAddresses = adapterAddresses->Next) {
119     processor.ProcessAdapterAddress(adapterAddresses);
120   }
121   return processor.mac_address();
122 }
123
124 std::string GetMacAddressFromGetIfTable2(
125     const IsValidMacAddressCallback& is_valid_mac_address) {
126   base::ThreadRestrictions::AssertIOAllowed();
127
128   // This is available on Vista+ only.
129   base::ScopedNativeLibrary library(base::FilePath(L"Iphlpapi.dll"));
130
131   typedef DWORD (NETIOAPI_API_ *GetIfTablePtr)(PMIB_IF_TABLE2*);
132   typedef void (NETIOAPI_API_ *FreeMibTablePtr)(PMIB_IF_TABLE2);
133
134   GetIfTablePtr getIfTable = reinterpret_cast<GetIfTablePtr>(
135       library.GetFunctionPointer("GetIfTable2"));
136   FreeMibTablePtr freeMibTablePtr = reinterpret_cast<FreeMibTablePtr>(
137       library.GetFunctionPointer("FreeMibTable"));
138   if (getIfTable == NULL || freeMibTablePtr == NULL) {
139     VLOG(ERROR) << "Could not get proc addresses for machine identifier.";
140     return "";
141   }
142
143   PMIB_IF_TABLE2  ifTable = NULL;
144   DWORD result = getIfTable(&ifTable);
145   if (result != NO_ERROR || ifTable == NULL) {
146     VLOG(ERROR) << "GetIfTable failed with error " << result;
147     return "";
148   }
149
150   MacAddressProcessor processor(is_valid_mac_address);
151   for (size_t i = 0; i < ifTable->NumEntries; i++) {
152     processor.ProcessInterfaceRow(&(ifTable->Table[i]));
153   }
154
155   if (ifTable != NULL) {
156     freeMibTablePtr(ifTable);
157     ifTable = NULL;
158   }
159   return processor.mac_address();
160 }
161
162 void GetMacAddress(const IsValidMacAddressCallback& is_valid_mac_address,
163                    const DeviceId::IdCallback& callback) {
164   base::ThreadRestrictions::AssertIOAllowed();
165
166   std::string mac_address =
167       GetMacAddressFromGetAdaptersAddresses(is_valid_mac_address);
168   if (mac_address.empty())
169     mac_address = GetMacAddressFromGetIfTable2(is_valid_mac_address);
170
171   static bool error_logged = false;
172   if (mac_address.empty() && !error_logged) {
173     error_logged = true;
174     LOG(ERROR) << "Could not find appropriate MAC address.";
175   }
176
177   content::BrowserThread::PostTask(
178       content::BrowserThread::UI,
179       FROM_HERE,
180       base::Bind(callback, mac_address));
181 }
182
183 std::string GetRlzMachineId() {
184 #if defined(ENABLE_RLZ)
185   std::string machine_id;
186   if (!rlz_lib::GetMachineId(&machine_id))
187     return "";
188   return machine_id;
189 #else
190   return "";
191 #endif
192 }
193
194 void GetMacAddressCallback(const DeviceId::IdCallback& callback,
195                            const std::string& mac_address) {
196   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
197
198   std::string machine_id = GetRlzMachineId();
199   if (mac_address.empty() || machine_id.empty()) {
200     callback.Run("");
201     return;
202   }
203   callback.Run(mac_address + machine_id);
204 }
205
206 }  // namespace
207
208 namespace extensions {
209 namespace api {
210
211 // static
212 void DeviceId::GetRawDeviceId(const IdCallback& callback) {
213   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
214
215   content::BrowserThread::PostTask(
216       content::BrowserThread::FILE,
217       FROM_HERE,
218       base::Bind(GetMacAddress,
219         base::Bind(DeviceId::IsValidMacAddress),
220         base::Bind(GetMacAddressCallback, callback)));
221 }
222
223 }  // namespace api
224 }  // namespace extensions