Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / music_manager_private / device_id_linux.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 #include <sys/socket.h>  // Must be included before ifaddrs.h.
8 #include <ifaddrs.h>
9 #include <net/if.h>
10 #include <sys/ioctl.h>
11
12 #include <map>
13
14 #include "base/bind.h"
15 #include "base/file_util.h"
16 #include "base/files/file_enumerator.h"
17 #include "base/files/file_path.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h"
20 #include "base/threading/thread_restrictions.h"
21 #include "content/public/browser/browser_thread.h"
22
23 namespace {
24
25 using extensions::api::DeviceId;
26
27 typedef base::Callback<bool(const void* bytes, size_t size)>
28     IsValidMacAddressCallback;
29
30 const char kDiskByUuidDirectoryName[] = "/dev/disk/by-uuid";
31 const char* kDeviceNames[] = {
32   "sda1", "hda1", "dm-0", "xvda1", "sda2", "hda2", "dm-1", "xvda2",
33 };
34 // Fedora 15 uses biosdevname feature where Embedded ethernet uses the
35 // "em" prefix and PCI cards use the p[0-9]c[0-9] format based on PCI
36 // slot and card information.
37 const char* kNetDeviceNamePrefixes[] = {
38    "eth", "em", "en", "wl", "ww", "p0", "p1", "p2", "p3", "p4", "p5", "p6",
39    "p7", "p8", "p9", "wlan"
40 };
41
42 // Map from device name to disk uuid
43 typedef std::map<base::FilePath, base::FilePath> DiskEntries;
44
45 std::string GetDiskUuid() {
46   base::ThreadRestrictions::AssertIOAllowed();
47
48   DiskEntries disk_uuids;
49   base::FileEnumerator files(base::FilePath(kDiskByUuidDirectoryName),
50                              false,  // Recursive.
51                              base::FileEnumerator::FILES);
52   do {
53     base::FilePath file_path = files.Next();
54     if (file_path.empty())
55       break;
56
57     base::FilePath target_path;
58     if (!base::ReadSymbolicLink(file_path, &target_path))
59       continue;
60
61     base::FilePath device_name = target_path.BaseName();
62     base::FilePath disk_uuid = file_path.BaseName();
63     disk_uuids[device_name] = disk_uuid;
64   } while (true);
65
66   // Look for first device name matching an entry of |kDeviceNames|.
67   std::string result;
68   for (size_t i = 0; i < arraysize(kDeviceNames); i++) {
69     DiskEntries::iterator it =
70         disk_uuids.find(base::FilePath(kDeviceNames[i]));
71     if (it != disk_uuids.end()) {
72       DVLOG(1) << "Returning uuid: \"" << it->second.value()
73                << "\" for device \"" << it->first.value() << "\"";
74       result = it->second.value();
75       break;
76     }
77   }
78
79   // Log failure (at most once) for diagnostic purposes.
80   static bool error_logged = false;
81   if (result.empty() && !error_logged) {
82     error_logged = true;
83     LOG(ERROR) << "Could not find appropriate disk uuid.";
84     for (DiskEntries::iterator it = disk_uuids.begin();
85         it != disk_uuids.end(); ++it) {
86       LOG(ERROR) << "  DeviceID=" << it->first.value() << ", uuid="
87                  << it->second.value();
88     }
89   }
90
91   return result;
92 }
93
94 class MacAddressProcessor {
95  public:
96   explicit MacAddressProcessor(
97       const IsValidMacAddressCallback& is_valid_mac_address)
98       : is_valid_mac_address_(is_valid_mac_address) {
99   }
100
101   bool ProcessInterface(struct ifaddrs *ifaddr,
102                         const char* prefixes[],
103                         size_t prefixes_count) {
104     const int MAC_LENGTH = 6;
105     struct ifreq ifinfo;
106
107     memset(&ifinfo, 0, sizeof(ifinfo));
108     strncpy(ifinfo.ifr_name, ifaddr->ifa_name, sizeof(ifinfo.ifr_name) - 1);
109
110     int sd = socket(AF_INET, SOCK_DGRAM, 0);
111     int result = ioctl(sd, SIOCGIFHWADDR, &ifinfo);
112     close(sd);
113
114     if (result != 0)
115       return true;
116
117     const char* mac_address =
118         static_cast<const char*>(ifinfo.ifr_hwaddr.sa_data);
119     if (!is_valid_mac_address_.Run(mac_address, MAC_LENGTH))
120       return true;
121
122     if (!IsValidPrefix(ifinfo.ifr_name, prefixes, prefixes_count))
123       return true;
124
125     // Got one!
126     found_mac_address_ =
127         StringToLowerASCII(base::HexEncode(mac_address, MAC_LENGTH));
128     return false;
129   }
130
131   std::string mac_address() const { return found_mac_address_; }
132
133  private:
134   bool IsValidPrefix(const char* name,
135                      const char* prefixes[],
136                      size_t prefixes_count) {
137     for (size_t i = 0; i < prefixes_count; i++) {
138       if (strncmp(prefixes[i], name, strlen(prefixes[i])) == 0)
139         return true;
140     }
141     return false;
142   }
143
144   const IsValidMacAddressCallback& is_valid_mac_address_;
145   std::string found_mac_address_;
146 };
147
148 std::string GetMacAddress(
149     const IsValidMacAddressCallback& is_valid_mac_address) {
150   base::ThreadRestrictions::AssertIOAllowed();
151
152   struct ifaddrs* ifaddrs;
153   int rv = getifaddrs(&ifaddrs);
154   if (rv < 0) {
155     PLOG(ERROR) << "getifaddrs failed " << rv;
156     return "";
157   }
158
159   MacAddressProcessor processor(is_valid_mac_address);
160   for (struct ifaddrs* ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
161     bool keep_going = processor.ProcessInterface(
162         ifa, kNetDeviceNamePrefixes, arraysize(kNetDeviceNamePrefixes));
163     if (!keep_going)
164       break;
165   }
166   freeifaddrs(ifaddrs);
167   return processor.mac_address();
168 }
169
170 void GetRawDeviceIdImpl(const IsValidMacAddressCallback& is_valid_mac_address,
171                         const DeviceId::IdCallback& callback) {
172   base::ThreadRestrictions::AssertIOAllowed();
173
174   std::string disk_id = GetDiskUuid();
175   std::string mac_address = GetMacAddress(is_valid_mac_address);
176
177   std::string raw_device_id;
178   if (!mac_address.empty() && !disk_id.empty()) {
179     raw_device_id = mac_address + disk_id;
180   }
181
182   content::BrowserThread::PostTask(
183       content::BrowserThread::UI,
184       FROM_HERE,
185       base::Bind(callback, raw_device_id));
186 }
187
188 }  // namespace
189
190 namespace extensions {
191 namespace api {
192
193 // static
194 void DeviceId::GetRawDeviceId(const IdCallback& callback) {
195   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
196
197   content::BrowserThread::PostTask(
198       content::BrowserThread::FILE,
199       FROM_HERE,
200       base::Bind(GetRawDeviceIdImpl,
201           base::Bind(DeviceId::IsValidMacAddress),
202           callback));
203 }
204
205 }  // namespace api
206 }  // namespace extensions