Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 040dffdb authored by Steve Fung's avatar Steve Fung Committed by ChromeOS Commit Bot
Browse files

crash: Convert list_proxies to chromeos-dbus-bindings generator

Switch list_proxies to using chromeos-dbus-bindings generator
in order to remove the glib dependency.

BUG=brillo:89
TEST=`FEATURES=test emerge-panther crash-reporter`
TEST=manually tested `list_proxies --quiet      \
       https://clieents2.google.com/cr/report`

Change-Id: Ic52277b2e14514376f4d55e627e1651d9ef566c5
Reviewed-on: https://chromium-review.googlesource.com/248781


Reviewed-by: default avatarDan Erat <derat@chromium.org>
Trybot-Ready: Dan Erat <derat@chromium.org>
Commit-Queue: Steve Fung <stevefung@chromium.org>
Tested-by: default avatarSteve Fung <stevefung@chromium.org>
parent f5767af0
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -6,7 +6,6 @@
    'variables': {
      'deps': [
        'libchromeos-<(libbase_ver)',
        'dbus-glib-1',
      ],
    },
  },
@@ -16,8 +15,6 @@
      'type': 'static_library',
      'variables': {
        'exported_deps': [
          'glib-2.0',
          'gobject-2.0',
          'libchrome-<(libbase_ver)',
          'libpcrecpp',
        ],
@@ -68,7 +65,6 @@
      'variables': {
        'deps': [
          'dbus-1',
          'dbus-glib-1',
          'libmetrics-<(libbase_ver)',
        ],
      },
@@ -85,13 +81,24 @@
      'variables': {
        'deps': [
          'dbus-1',
          'dbus-glib-1',
          'libchrome-<(libbase_ver)',
        ],
      },
      'sources': [
        'list_proxies.cc',
      ],
      'actions': [
        {
          'action_name': 'generate-lib-cros-service-proxies',
          'variables': {
            'proxy_output_file': 'include/libcrosservice/dbus-proxies.h'
          },
          'sources': [
            './dbus_bindings/org.chromium.LibCrosService.xml',
          ],
          'includes': ['../common-mk/generate-dbus-proxies.gypi'],
        },
      ],
    },
    {
      'target_name': 'warn_collector',
+20 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8" ?>

<node name="/org/chromium/LibCrosService"
      xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
  <interface name="org.chromium.LibCrosServiceInterface">
    <method name="ResolveNetworkProxy">
      <arg name="source_url" type="s" direction="in"/>
      <arg name="signal_interface" type="s" direction="in"/>
      <arg name="signal_name" type="s" direction="in"/>
      <annotation name="org.chromium.DBus.Method.Kind" value="simple"/>
    </method>
  </interface>
  <interface name="org.chromium.CrashReporterLibcrosProxyResolvedInterface">
    <signal name="ProxyResolved">
      <arg name="source_url" type="s" direction="out"/>
      <arg name="proxy_info" type="s" direction="out"/>
      <arg name="error_message" type="s" direction="out"/>
    </signal>
  </interface>
</node>
+153 −119
Original line number Diff line number Diff line
@@ -2,35 +2,36 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <dbus/dbus-glib-lowlevel.h>
#include <glib.h>
#include <sysexits.h>
#include <unistd.h>  // for isatty()

#include <deque>
#include <string>
#include <vector>

#include <base/cancelable_callback.h>
#include <base/command_line.h>
#include <base/files/file_util.h>
#include <base/memory/weak_ptr.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_tokenizer.h>
#include <base/strings/string_util.h>
#include <base/values.h>
#include <chromeos/dbus/dbus.h>
#include <chromeos/daemons/dbus_daemon.h>
#include <chromeos/syslog_logging.h>

const char kLibCrosProxyResolveSignalInterface[] =
#include "libcrosservice/dbus-proxies.h"

using std::unique_ptr;

namespace {

const char kLibCrosProxyResolvedSignalInterface[] =
    "org.chromium.CrashReporterLibcrosProxyResolvedInterface";
const char kLibCrosProxyResolveName[] = "ProxyResolved";
const char kLibCrosServiceInterface[] = "org.chromium.LibCrosServiceInterface";
const char kLibCrosProxyResolvedName[] = "ProxyResolved";
const char kLibCrosServiceName[] = "org.chromium.LibCrosService";
const char kLibCrosServicePath[] = "/org/chromium/LibCrosService";
const char kLibCrosServiceResolveNetworkProxyMethodName[] =
    "ResolveNetworkProxy";
const char kNoProxy[] = "direct://";

namespace switches {

const unsigned kTimeoutDefault = 5;
const int kTimeoutDefaultSeconds = 5;

const char kHelp[] = "help";
const char kQuiet[] = "quiet";
@@ -46,19 +47,11 @@ const char kHelpMessage[] =
    "  --timeout=N  Set timeout for browser resolving proxies (default is 5)\n"
    "  --help       Show this help.\n";

}  // namespace switches

static const char *GetGErrorMessage(const GError *error) {
  if (!error)
    return "Unknown error.";
  return error->message;
}

// Copied from src/update_engine/chrome_browser_proxy_resolver.cc
// Parses the browser's answer for resolved proxies.  It returns a
// list of strings, each of which is a resolved proxy.
std::deque<std::string> ParseProxyString(const std::string &input) {
  std::deque<std::string> ret;
std::vector<std::string> ParseProxyString(const std::string& input) {
  std::vector<std::string> ret;
  // Some of this code taken from
  // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_server.cc and
  // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list.cc
@@ -99,130 +92,173 @@ std::deque<std::string> ParseProxyString(const std::string &input) {
  return ret;
}

// Define a signal-watcher class to handle the D-Bus signal sent to us when
// the browser answers our request to resolve proxies.
class BrowserProxyResolvedSignalWatcher : public chromeos::dbus::SignalWatcher {
// A class for interfacing with Chrome to resolve proxies for a given source
// url.  The class is initialized with the given source url to check, the
// signal interface and name that Chrome will reply to, and how long to wait
// for the resolve request to timeout.  Once initialized, the Run() function
// must be called, which blocks on the D-Bus call to Chrome.  The call returns
// after either the timeout or the proxy has been resolved.  The resolved
// proxies can then be accessed through the proxies() function.
class ProxyResolver : public chromeos::DBusDaemon {
 public:
  explicit BrowserProxyResolvedSignalWatcher(GMainLoop *main_loop,
                                             std::deque<std::string> *proxies)
      : main_loop_(main_loop), proxies_(proxies) { }

  void OnSignal(DBusMessage *message) override {
    // Get args
    char *source_url = nullptr;
    char *proxy_list = nullptr;
    char *error = nullptr;
    DBusError arg_error;
    dbus_error_init(&arg_error);
    if (!dbus_message_get_args(message, &arg_error,
                               DBUS_TYPE_STRING, &source_url,
                               DBUS_TYPE_STRING, &proxy_list,
                               DBUS_TYPE_STRING, &error,
                               DBUS_TYPE_INVALID)) {
      LOG(ERROR) << "Error reading D-Bus signal";
      return;
    }
    if (!source_url || !proxy_list) {
      LOG(ERROR) << "Error getting url, proxy list from D-Bus signal";
      return;
  ProxyResolver(const std::string& source_url,
                const std::string& signal_interface,
                const std::string& signal_name,
                base::TimeDelta timeout)
      : source_url_(source_url),
        signal_interface_(signal_interface),
        signal_name_(signal_name),
        timeout_(timeout),
        weak_ptr_factory_(this),
        timeout_callback_(base::Bind(&ProxyResolver::HandleBrowserTimeout,
                                     weak_ptr_factory_.GetWeakPtr())) {}

  ~ProxyResolver() override {}

  const std::vector<std::string>& proxies() {
    return proxies_;
  }

    const std::deque<std::string> &proxies = ParseProxyString(proxy_list);
    for (std::deque<std::string>::const_iterator it = proxies.begin();
         it != proxies.end(); ++it) {
      LOG(INFO) << "Found proxy via browser signal: " << (*it).c_str();
      proxies_->push_back(*it);
    }
  int Run() override {
    // Add task for if the browser proxy call times out.
    base::MessageLoop::current()->PostDelayedTask(
        FROM_HERE,
        timeout_callback_.callback(),
        timeout_);

    g_main_loop_quit(main_loop_);
    return chromeos::DBusDaemon::Run();
  }

 private:
  GMainLoop *main_loop_;
  std::deque<std::string> *proxies_;
};

static gboolean HandleBrowserTimeout(void *data) {
  GMainLoop *main_loop = reinterpret_cast<GMainLoop *>(data);
 protected:
  // If the browser times out, quit the run loop.
  void HandleBrowserTimeout() {
    LOG(ERROR) << "Timeout while waiting for browser to resolve proxy";
  g_main_loop_quit(main_loop);
  return false;  // only call once
    Quit();
  }

static bool ShowBrowserProxies(std::string url, unsigned timeout) {
  GMainLoop *main_loop = g_main_loop_new(nullptr, false);
  // If the signal handler connects successfully, call the browser's
  // ResolveNetworkProxy D-Bus method.  Otherwise, don't do anything and let
  // the timeout task quit the run loop.
  void HandleDBusSignalConnected(const std::string& interface,
                                 const std::string& signal,
                                 bool success) {
    if (!success) {
      LOG(ERROR) << "Could not connect to signal " << interface << "."
                 << signal;
      timeout_callback_.Cancel();
      Quit();
      return;
    }

  chromeos::dbus::BusConnection dbus = chromeos::dbus::GetSystemBusConnection();
  if (!dbus.HasConnection()) {
    LOG(ERROR) << "Error connecting to system D-Bus";
    return false;
    chromeos::ErrorPtr error;
    call_proxy_->ResolveNetworkProxy(source_url_,
                                     signal_interface_,
                                     signal_name_,
                                     &error);

    if (error) {
      LOG(ERROR) << "Call to ResolveNetworkProxy failed: "
                 << error->GetMessage();
      timeout_callback_.Cancel();
      Quit();
    }
  chromeos::dbus::Proxy browser_proxy(dbus,
                                      kLibCrosServiceName,
                                      kLibCrosServicePath,
                                      kLibCrosServiceInterface);
  if (!browser_proxy) {
    LOG(ERROR) << "Error creating D-Bus proxy to interface "
               << "'" << kLibCrosServiceName << "'";
    return false;
  }

  // Watch for a proxy-resolved signal sent to us
  std::deque<std::string> proxies;
  BrowserProxyResolvedSignalWatcher proxy_resolver(main_loop, &proxies);
  proxy_resolver.StartMonitoring(kLibCrosProxyResolveSignalInterface,
                                 kLibCrosProxyResolveName);

  // Request the proxies for our URL.  The answer is sent to us via a
  // proxy-resolved signal.
  GError *gerror = nullptr;
  if (!dbus_g_proxy_call(browser_proxy.gproxy(),
                         kLibCrosServiceResolveNetworkProxyMethodName,
                         &gerror,
                         G_TYPE_STRING, url.c_str(),
                         G_TYPE_STRING, kLibCrosProxyResolveSignalInterface,
                         G_TYPE_STRING, kLibCrosProxyResolveName,
                         G_TYPE_INVALID, G_TYPE_INVALID)) {
    LOG(ERROR) << "Error performing D-Bus proxy call "
               << "'" << kLibCrosServiceResolveNetworkProxyMethodName << "'"
               << ": " << GetGErrorMessage(gerror);
    return false;
  // Handle incoming ProxyResolved signal.
  void HandleProxyResolvedSignal(const std::string& source_url,
                                 const std::string& proxy_info,
                                 const std::string& error_message) {
    timeout_callback_.Cancel();
    proxies_ = ParseProxyString(proxy_info);
    LOG(INFO) << "Found proxies via browser signal: "
              << JoinString(proxies_, 'x');

    Quit();
  }

  // Setup a timeout in case the browser doesn't respond with our signal
  g_timeout_add_seconds(timeout, &HandleBrowserTimeout, main_loop);
  int OnInit() override {
    int return_code = chromeos::DBusDaemon::OnInit();
    if (return_code != EX_OK)
      return return_code;

    // Initialize D-Bus proxies.
    call_proxy_.reset(
        new org::chromium::LibCrosServiceInterfaceProxy(bus_,
                                                        kLibCrosServiceName));
    signal_proxy_.reset(
        new org::chromium::CrashReporterLibcrosProxyResolvedInterfaceProxy(
            bus_,
            kLibCrosServiceName));

    // Set up the D-Bus signal handler.
    // TODO(crbug.com/446115): Update ResolveNetworkProxy call to use an
    //     asynchronous return value rather than a return signal.
    signal_proxy_->RegisterProxyResolvedSignalHandler(
        base::Bind(&ProxyResolver::HandleProxyResolvedSignal,
                   weak_ptr_factory_.GetWeakPtr()),
        base::Bind(&ProxyResolver::HandleDBusSignalConnected,
                   weak_ptr_factory_.GetWeakPtr()));

    return EX_OK;
  }

 private:
  unique_ptr<org::chromium::LibCrosServiceInterfaceProxy> call_proxy_;
  unique_ptr<org::chromium::CrashReporterLibcrosProxyResolvedInterfaceProxy>
      signal_proxy_;

  const std::string source_url_;
  const std::string signal_interface_;
  const std::string signal_name_;
  base::TimeDelta timeout_;

  // Loop until we either get the proxy-resolved signal, or until the
  // timeout is reached.
  g_main_loop_run(main_loop);
  std::vector<std::string> proxies_;
  base::WeakPtrFactory<ProxyResolver> weak_ptr_factory_;

  // If there are no proxies, then we failed to get the proxy-resolved
  // signal (e.g. timeout was reached).
  base::CancelableClosure timeout_callback_;

  DISALLOW_COPY_AND_ASSIGN(ProxyResolver);
};

static bool ShowBrowserProxies(std::string url, base::TimeDelta timeout) {
  // Initialize and run the proxy resolver to watch for signals.
  ProxyResolver resolver(url,
                         kLibCrosProxyResolvedSignalInterface,
                         kLibCrosProxyResolvedName,
                         timeout);
  resolver.Run();

  std::vector<std::string> proxies = resolver.proxies();

  // If proxies is empty, then the timeout was reached waiting for the proxy
  // resolved signal.  If no proxies are defined, proxies will be populated
  // with "direct://".
  if (proxies.empty())
    return false;

  for (std::deque<std::string>::const_iterator it = proxies.begin();
       it != proxies.end(); ++it) {
    printf("%s\n", (*it).c_str());
  for (const auto& proxy : proxies) {
    printf("%s\n", proxy.c_str());
  }
  return true;
}

}  // namespace

int main(int argc, char *argv[]) {
  CommandLine::Init(argc, argv);
  CommandLine* cl = CommandLine::ForCurrentProcess();

  if (cl->HasSwitch(switches::kHelp)) {
    LOG(INFO) << switches::kHelpMessage;
  if (cl->HasSwitch(kHelp)) {
    LOG(INFO) << kHelpMessage;
    return 0;
  }

  bool quiet = cl->HasSwitch(switches::kQuiet);
  bool verbose = cl->HasSwitch(switches::kVerbose);
  bool quiet = cl->HasSwitch(kQuiet);
  bool verbose = cl->HasSwitch(kVerbose);

  unsigned timeout = switches::kTimeoutDefault;
  std::string str_timeout = cl->GetSwitchValueASCII(switches::kTimeout);
  if (!str_timeout.empty() && !base::StringToUint(str_timeout, &timeout)) {
  int timeout = kTimeoutDefaultSeconds;
  std::string str_timeout = cl->GetSwitchValueASCII(kTimeout);
  if (!str_timeout.empty() && !base::StringToInt(str_timeout, &timeout)) {
    LOG(ERROR) << "Invalid timeout value: " << str_timeout;
    return 1;
  }
@@ -236,8 +272,6 @@ int main(int argc, char *argv[]) {
    init_flags |= chromeos::kLogToStderr;
  chromeos::InitLog(init_flags);

  ::g_type_init();

  std::string url;
  CommandLine::StringVector urls = cl->GetArgs();
  if (!urls.empty()) {
@@ -247,7 +281,7 @@ int main(int argc, char *argv[]) {
    LOG(INFO) << "Resolving proxies without URL";
  }

  if (!ShowBrowserProxies(url, timeout)) {
  if (!ShowBrowserProxies(url, base::TimeDelta::FromSeconds(timeout))) {
    LOG(ERROR) << "Error resolving proxies via the browser";
    LOG(INFO) << "Assuming direct proxy";
    printf("%s\n", kNoProxy);