blob: c1c8bad7e7dcecf23e17b2853673b8e93d8554b6 [file] [log] [blame]
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <cassert>
#include <cerrno>
#include <memory>
#include <base/bind.h>
#include <base/command_line.h>
#include <base/logging.h>
#include <base/rand_util.h>
#include <base/strings/string_number_conversions.h>
#include <metrics/metrics_library.h>
#include "p2p/client/peer_selector.h"
#include "p2p/client/service_finder.h"
#include "p2p/common/clock.h"
#include "p2p/common/constants.h"
#include "p2p/common/util.h"
using std::map;
using std::string;
using std::vector;
/* Global pointer to the PeerSelector being used. Only used from the signal
* handler of SIGTERM. */
static p2p::client::PeerSelector* volatile global_peer_selector = NULL;
static void sigterm_handler(int signum) {
/* This function is non-reentrant since is only used to handle SIGTERM.
* A second SIGTERM signal will wait until this call finishes. */
if (global_peer_selector)
global_peer_selector->Abort();
}
static void Usage(FILE* output) {
fprintf(output,
"Usage:\n"
" p2p-client [OPTION..]\n"
"\n"
"Options:\n"
" --help Show help options\n"
" --list-all Scan network and list available files\n"
" --list-urls=ID Like --list-all but only show peers for ID\n"
" --get-url=ID Scan for ID and pick a suitable peer\n"
" --num-connections Show total number of connections in the LAN\n"
" -v=NUMBER Verbosity level (default: 0)\n"
" --minimum-size=NUM When used with --get-url, scans for files\n"
" with at least NUM bytes (default: 1).\n"
"\n");
}
// Lists all URLs discovered via |finder|. If |id| is not the empty
// string then only lists URLs matching it.
static void ListUrls(p2p::client::ServiceFinder* finder,
const std::string& id) {
vector<string> files = finder->AvailableFiles();
for (auto const& file_name : files) {
if (id == "" || file_name == id) {
printf("%s\n", file_name.c_str());
vector<const p2p::client::Peer*> peers =
finder->GetPeersForFile(file_name);
for (auto const& peer : peers) {
map<string, size_t>::const_iterator file_size_it =
peer->files.find(file_name);
printf(" address %s, port %d, size %zu, num_connections %d\n",
peer->address.c_str(), peer->port,
(file_size_it == peer->files.end() ? -1 : file_size_it->second),
peer->num_connections);
}
}
}
}
int main(int argc, char* argv[]) {
std::unique_ptr<p2p::client::ServiceFinder> finder;
base::CommandLine::Init(argc, argv);
logging::LoggingSettings logging_settings;
logging_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
logging_settings.lock_log = logging::LOCK_LOG_FILE;
logging_settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
logging::InitLogging(logging_settings);
p2p::util::SetupSyslog("p2p-client", true /* include_pid */);
base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
// If help is requested, show usage and exit immediately
if (cl->HasSwitch("help")) {
Usage(stdout);
return 0;
}
// Get us a ServiceFinder and look up all peers - this takes a couple
// of seconds. This can fail if e.g. avahi-daemon is not running.
finder.reset(p2p::client::ServiceFinder::Construct());
if (finder == NULL)
return 1;
p2p::common::Clock clock;
p2p::client::PeerSelector peer_selector(finder.get(), &clock);
// The Metrics Library interface for reporting UMA stats.
if (cl->HasSwitch("list-all")) {
finder->Lookup();
ListUrls(finder.get(), "");
} else if (cl->HasSwitch("num-connections")) {
finder->Lookup();
int num_connections = finder->NumTotalConnections();
printf("%d\n", num_connections);
} else if (cl->HasSwitch("get-url")) {
string id = cl->GetSwitchValueNative("get-url");
uint64_t minimum_size = 1;
if (cl->HasSwitch("minimum-size")) {
string minimum_size_str = cl->GetSwitchValueNative("minimum-size");
if (!base::StringToUint64(minimum_size_str, &minimum_size)) {
LOG(ERROR) << "Invalid --minimum-size argument";
return 1;
}
}
// Register the SIGTERM signal handler in order to abort the
// GetUrlAndWait() call, but reporting the metric.
global_peer_selector = &peer_selector;
signal(SIGTERM, sigterm_handler);
string url = peer_selector.GetUrlAndWait(id, minimum_size);
// Remove the global pointer reference to avoid a Abort() call due a
// SIGTERM after the pointed object is destroyed.
global_peer_selector = NULL;
// Report the metrics.
MetricsLibrary metrics_lib;
peer_selector.ReportMetrics(&metrics_lib);
if (url == "")
return 1;
printf("%s\n", url.c_str());
} else if (cl->HasSwitch("list-urls")) {
string id = cl->GetSwitchValueNative("list-urls");
finder->Lookup();
ListUrls(finder.get(), id);
} else {
Usage(stderr);
return 1;
}
return 0;
}