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.
5 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
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.
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"
27 #if defined(ENABLE_RLZ)
28 #include "rlz/lib/machine_id.h"
33 using extensions::api::DeviceId
;
35 typedef base::Callback
<bool(const void* bytes
, size_t size
)>
36 IsValidMacAddressCallback
;
38 class MacAddressProcessor
{
40 MacAddressProcessor(const IsValidMacAddressCallback
& is_valid_mac_address
)
41 : is_valid_mac_address_(is_valid_mac_address
),
42 found_index_(ULONG_MAX
) {
45 // Iterate through the interfaces, looking for the valid MAC address with the
47 void ProcessAdapterAddress(PIP_ADAPTER_ADDRESSES address
) {
48 if (address
->IfType
== IF_TYPE_TUNNEL
)
51 ProcessPhysicalAddress(address
->IfIndex
,
52 address
->PhysicalAddress
,
53 address
->PhysicalAddressLength
);
56 void ProcessInterfaceRow(const PMIB_IF_ROW2 row
) {
57 if (row
->Type
== IF_TYPE_TUNNEL
||
58 !row
->InterfaceAndOperStatusFlags
.HardwareInterface
) {
62 ProcessPhysicalAddress(row
->InterfaceIndex
,
64 row
->PhysicalAddressLength
);
67 std::string
mac_address() const { return found_mac_address_
; }
70 void ProcessPhysicalAddress(NET_IFINDEX index
,
73 if (index
>= found_index_
|| size
== 0)
76 if (!is_valid_mac_address_
.Run(bytes
, size
))
79 found_mac_address_
= base::ToLowerASCII(base::HexEncode(bytes
, size
));
83 const IsValidMacAddressCallback
& is_valid_mac_address_
;
84 std::string found_mac_address_
;
85 NET_IFINDEX found_index_
;
88 std::string
GetMacAddressFromGetAdaptersAddresses(
89 const IsValidMacAddressCallback
& is_valid_mac_address
) {
90 base::ThreadRestrictions::AssertIOAllowed();
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());
102 DWORD result
= GetAdaptersAddresses(AF_UNSPEC
, flags
, 0,
103 adapterAddresses
, &bufferSize
);
104 if (result
== ERROR_BUFFER_OVERFLOW
) {
105 buffer
.resize(bufferSize
);
107 reinterpret_cast<PIP_ADAPTER_ADDRESSES
>(&buffer
.front());
108 result
= GetAdaptersAddresses(AF_UNSPEC
, flags
, 0,
109 adapterAddresses
, &bufferSize
);
112 if (result
!= NO_ERROR
) {
113 VLOG(ERROR
) << "GetAdapatersAddresses failed with error " << result
;
117 MacAddressProcessor
processor(is_valid_mac_address
);
118 for (; adapterAddresses
!= NULL
; adapterAddresses
= adapterAddresses
->Next
) {
119 processor
.ProcessAdapterAddress(adapterAddresses
);
121 return processor
.mac_address();
124 std::string
GetMacAddressFromGetIfTable2(
125 const IsValidMacAddressCallback
& is_valid_mac_address
) {
126 base::ThreadRestrictions::AssertIOAllowed();
128 // This is available on Vista+ only.
129 base::ScopedNativeLibrary
library(base::FilePath(L
"Iphlpapi.dll"));
131 typedef DWORD (NETIOAPI_API_
*GetIfTablePtr
)(PMIB_IF_TABLE2
*);
132 typedef void (NETIOAPI_API_
*FreeMibTablePtr
)(PMIB_IF_TABLE2
);
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.";
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
;
150 MacAddressProcessor
processor(is_valid_mac_address
);
151 for (size_t i
= 0; i
< ifTable
->NumEntries
; i
++) {
152 processor
.ProcessInterfaceRow(&(ifTable
->Table
[i
]));
155 if (ifTable
!= NULL
) {
156 freeMibTablePtr(ifTable
);
159 return processor
.mac_address();
162 void GetMacAddress(const IsValidMacAddressCallback
& is_valid_mac_address
,
163 const DeviceId::IdCallback
& callback
) {
164 base::ThreadRestrictions::AssertIOAllowed();
166 std::string mac_address
=
167 GetMacAddressFromGetAdaptersAddresses(is_valid_mac_address
);
168 if (mac_address
.empty())
169 mac_address
= GetMacAddressFromGetIfTable2(is_valid_mac_address
);
171 static bool error_logged
= false;
172 if (mac_address
.empty() && !error_logged
) {
174 LOG(ERROR
) << "Could not find appropriate MAC address.";
177 content::BrowserThread::PostTask(
178 content::BrowserThread::UI
,
180 base::Bind(callback
, mac_address
));
183 std::string
GetRlzMachineId() {
184 #if defined(ENABLE_RLZ)
185 std::string machine_id
;
186 if (!rlz_lib::GetMachineId(&machine_id
))
194 void GetMacAddressCallback(const DeviceId::IdCallback
& callback
,
195 const std::string
& mac_address
) {
196 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
198 std::string machine_id
= GetRlzMachineId();
199 if (mac_address
.empty() || machine_id
.empty()) {
203 callback
.Run(mac_address
+ machine_id
);
208 namespace extensions
{
212 void DeviceId::GetRawDeviceId(const IdCallback
& callback
) {
213 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
215 content::BrowserThread::PostTask(
216 content::BrowserThread::FILE,
218 base::Bind(GetMacAddress
,
219 base::Bind(DeviceId::IsValidMacAddress
),
220 base::Bind(GetMacAddressCallback
, callback
)));
224 } // namespace extensions