Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / music_manager_private / device_id_linux.cc
index 87e6e45..a6e09c0 100644 (file)
@@ -4,26 +4,45 @@
 
 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
 
+#include <sys/socket.h>  // Must be included before ifaddrs.h.
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+
 #include <map>
 
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace {
 
+using extensions::api::DeviceId;
+
+typedef base::Callback<bool(const void* bytes, size_t size)>
+    IsValidMacAddressCallback;
+
 const char kDiskByUuidDirectoryName[] = "/dev/disk/by-uuid";
 const char* kDeviceNames[] = {
   "sda1", "hda1", "dm-0", "xvda1", "sda2", "hda2", "dm-1", "xvda2",
 };
+// Fedora 15 uses biosdevname feature where Embedded ethernet uses the
+// "em" prefix and PCI cards use the p[0-9]c[0-9] format based on PCI
+// slot and card information.
+const char* kNetDeviceNamePrefixes[] = {
+   "eth", "em", "en", "wl", "ww", "p0", "p1", "p2", "p3", "p4", "p5", "p6",
+   "p7", "p8", "p9", "wlan"
+};
 
 // Map from device name to disk uuid
 typedef std::map<base::FilePath, base::FilePath> DiskEntries;
 
-void GetDiskUuid(const extensions::api::DeviceId::IdCallback& callback) {
+std::string GetDiskUuid() {
   base::ThreadRestrictions::AssertIOAllowed();
 
   DiskEntries disk_uuids;
@@ -69,10 +88,101 @@ void GetDiskUuid(const extensions::api::DeviceId::IdCallback& callback) {
     }
   }
 
+  return result;
+}
+
+class MacAddressProcessor {
+ public:
+  explicit MacAddressProcessor(
+      const IsValidMacAddressCallback& is_valid_mac_address)
+      : is_valid_mac_address_(is_valid_mac_address) {
+  }
+
+  bool ProcessInterface(struct ifaddrs *ifaddr,
+                        const char* prefixes[],
+                        size_t prefixes_count) {
+    const int MAC_LENGTH = 6;
+    struct ifreq ifinfo;
+
+    memset(&ifinfo, 0, sizeof(ifinfo));
+    strncpy(ifinfo.ifr_name, ifaddr->ifa_name, sizeof(ifinfo.ifr_name) - 1);
+
+    int sd = socket(AF_INET, SOCK_DGRAM, 0);
+    int result = ioctl(sd, SIOCGIFHWADDR, &ifinfo);
+    close(sd);
+
+    if (result != 0)
+      return true;
+
+    const char* mac_address =
+        static_cast<const char*>(ifinfo.ifr_hwaddr.sa_data);
+    if (!is_valid_mac_address_.Run(mac_address, MAC_LENGTH))
+      return true;
+
+    if (!IsValidPrefix(ifinfo.ifr_name, prefixes, prefixes_count))
+      return true;
+
+    // Got one!
+    found_mac_address_ =
+        StringToLowerASCII(base::HexEncode(mac_address, MAC_LENGTH));
+    return false;
+  }
+
+  std::string mac_address() const { return found_mac_address_; }
+
+ private:
+  bool IsValidPrefix(const char* name,
+                     const char* prefixes[],
+                     size_t prefixes_count) {
+    for (size_t i = 0; i < prefixes_count; i++) {
+      if (strncmp(prefixes[i], name, strlen(prefixes[i])) == 0)
+        return true;
+    }
+    return false;
+  }
+
+  const IsValidMacAddressCallback& is_valid_mac_address_;
+  std::string found_mac_address_;
+};
+
+std::string GetMacAddress(
+    const IsValidMacAddressCallback& is_valid_mac_address) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  struct ifaddrs* ifaddrs;
+  int rv = getifaddrs(&ifaddrs);
+  if (rv < 0) {
+    PLOG(ERROR) << "getifaddrs failed " << rv;
+    return "";
+  }
+
+  MacAddressProcessor processor(is_valid_mac_address);
+  for (struct ifaddrs* ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+    bool keep_going = processor.ProcessInterface(
+        ifa, kNetDeviceNamePrefixes, arraysize(kNetDeviceNamePrefixes));
+    if (!keep_going)
+      break;
+  }
+  freeifaddrs(ifaddrs);
+  return processor.mac_address();
+}
+
+void GetRawDeviceIdImpl(const IsValidMacAddressCallback& is_valid_mac_address,
+                        const DeviceId::IdCallback& callback) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  std::string disk_id = GetDiskUuid();
+  std::string mac_address = GetMacAddress(is_valid_mac_address);
+
+  std::string raw_device_id;
+  if (!mac_address.empty() && !disk_id.empty()) {
+    raw_device_id = mac_address + disk_id;
+  }
+
   content::BrowserThread::PostTask(
       content::BrowserThread::UI,
       FROM_HERE,
-      base::Bind(callback, result));
+      base::Bind(callback, raw_device_id));
 }
 
 }  // namespace
@@ -87,7 +197,9 @@ void DeviceId::GetRawDeviceId(const IdCallback& callback) {
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(GetDiskUuid, callback));
+      base::Bind(GetRawDeviceIdImpl,
+          base::Bind(DeviceId::IsValidMacAddress),
+          callback));
 }
 
 }  // namespace api