1// Copyright 2014 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/media/wv_test_license_server_config.h"
6
7#include "base/command_line.h"
8#include "base/environment.h"
9#include "base/files/file_util.h"
10#include "base/path_service.h"
11#include "base/rand_util.h"
12#include "base/strings/stringprintf.h"
13#include "net/base/net_errors.h"
14#include "net/socket/tcp_server_socket.h"
15#include "net/test/python_utils.h"
16
17
18const uint16 kMinPort = 17000;
19const uint16 kPortRangeSize = 1000;
20
21// Widevine license server configuration files.
22const base::FilePath::CharType kKeysFileName[] =
23    FILE_PATH_LITERAL("keys.dat");
24const base::FilePath::CharType kPoliciesFileName[] =
25    FILE_PATH_LITERAL("policies.dat");
26const base::FilePath::CharType kProfilesFileName[] =
27    FILE_PATH_LITERAL("profiles.dat");
28
29// License server configuration files directory name relative to root.
30const base::FilePath::CharType kLicenseServerConfigDirName[] =
31    FILE_PATH_LITERAL("config");
32
33WVTestLicenseServerConfig::WVTestLicenseServerConfig() {
34}
35
36WVTestLicenseServerConfig::~WVTestLicenseServerConfig() {
37}
38
39bool WVTestLicenseServerConfig::GetServerCommandLine(
40    CommandLine* command_line) {
41  if (!GetPythonCommand(command_line)) {
42    LOG(ERROR) << "Could not get Python runtime command.";
43    return false;
44  }
45
46  // Add the Python protocol buffers files directory to Python path.
47  base::FilePath pyproto_dir;
48  if (!GetPyProtoPath(&pyproto_dir)) {
49    VLOG(0) << "Cannot find pyproto directory required by license server.";
50    return false;
51  }
52  AppendToPythonPath(pyproto_dir);
53
54  base::FilePath license_server_path;
55  GetLicenseServerPath(&license_server_path);
56  if (!base::PathExists(license_server_path)) {
57    VLOG(0) << "Missing license server file at " << license_server_path.value();
58    return false;
59  }
60
61  base::FilePath server_root;
62  GetLicenseServerRootPath(&server_root);
63  base::FilePath config_path = server_root.Append(kLicenseServerConfigDirName);
64
65  if (!base::PathExists(config_path.Append(kKeysFileName)) ||
66      !base::PathExists(config_path.Append(kPoliciesFileName)) ||
67      !base::PathExists(config_path.Append(kProfilesFileName))) {
68    VLOG(0) << "Missing license server configuration files.";
69    return false;
70  }
71
72  if (!SelectServerPort())
73    return false;
74
75  // Needed to dynamically load .so libraries used by license server.
76  // TODO(shadi): Remove need to set env variable once b/12932983 is fixed.
77#if defined(OS_LINUX)
78  scoped_ptr<base::Environment> env(base::Environment::Create());
79  const char kLibraryPathEnvVarName[] = "LD_LIBRARY_PATH";
80  std::string library_paths(license_server_path.DirName().value());
81  std::string old_path;
82  if (env->GetVar(kLibraryPathEnvVarName, &old_path))
83    library_paths.append(":").append(old_path);
84  env->SetVar(kLibraryPathEnvVarName, library_paths);
85#endif  // defined(OS_LINUX)
86
87  // Since it is a Python command line, we need to AppendArg instead of
88  // AppendSwitch so that the arguments are passed to the Python server instead
89  // of Python engine.
90  command_line->AppendArgPath(license_server_path);
91  command_line->AppendArg("-k");
92  command_line->AppendArgPath(config_path.Append(kKeysFileName));
93  command_line->AppendArg("-o");
94  command_line->AppendArgPath(config_path.Append(kPoliciesFileName));
95  command_line->AppendArg("-r");
96  command_line->AppendArgPath(config_path.Append(kProfilesFileName));
97  command_line->AppendArg(base::StringPrintf("--port=%u", port_));
98  return true;
99}
100
101bool WVTestLicenseServerConfig::SelectServerPort() {
102  // Try all ports within the range of kMinPort to (kMinPort + kPortRangeSize)
103  // Instead of starting from kMinPort, use a random port within that range.
104  net::IPAddressNumber address;
105  net::ParseIPLiteralToNumber("127.0.0.1", &address);
106  uint16 start_seed = base::RandInt(0, kPortRangeSize);
107  uint16 try_port = 0;
108  for (uint16 i = 0; i < kPortRangeSize; ++i) {
109    try_port = kMinPort + (start_seed + i) % kPortRangeSize;
110    net::NetLog::Source source;
111    net::TCPServerSocket sock(NULL, source);
112    if (sock.Listen(net::IPEndPoint(address, try_port), 1) == net::OK) {
113      port_ = try_port;
114      return true;
115    }
116  }
117  VLOG(0) << "Could not find an open port in the range of " <<  kMinPort <<
118             " to " << kMinPort + kPortRangeSize;
119  return false;
120}
121
122bool WVTestLicenseServerConfig::IsPlatformSupported() {
123#if defined(OS_LINUX) && defined(ARCH_CPU_X86_64)
124  return true;
125#else
126  return false;
127#endif  // defined(OS_LINUX)
128}
129
130std::string WVTestLicenseServerConfig::GetServerURL() {
131  return base::StringPrintf("http://localhost:%u/license_server", port_);
132}
133
134void WVTestLicenseServerConfig::GetLicenseServerPath(base::FilePath *path) {
135  base::FilePath server_root;
136  GetLicenseServerRootPath(&server_root);
137  // Platform-specific license server binary path relative to root.
138  *path =
139#if defined(OS_LINUX)
140    server_root.Append(FILE_PATH_LITERAL("linux"))
141               .Append(FILE_PATH_LITERAL("license_server.py"));
142#else
143    server_root.Append(FILE_PATH_LITERAL("unsupported_platform"));
144#endif  // defined(OS_LINUX)
145}
146
147void WVTestLicenseServerConfig::GetLicenseServerRootPath(
148    base::FilePath* path) {
149  base::FilePath source_root;
150  PathService::Get(base::DIR_SOURCE_ROOT, &source_root);
151  *path = source_root.Append(FILE_PATH_LITERAL("third_party"))
152                     .Append(FILE_PATH_LITERAL("widevine"))
153                     .Append(FILE_PATH_LITERAL("test"))
154                     .Append(FILE_PATH_LITERAL("license_server"));
155}
156