1
0
Fork 0
mirror of https://github.com/albfan/miraclecast.git synced 2025-03-09 23:38:56 +00:00

miraclectl: add scan commands

Three new commands that control scans on a given link are added:
 1) start-scan: Starts scanning in background for a given link
 2) stop-scan: Stops scanning in background for a given link
 3) scan: Does interactive scanning for a given link

The interactive scanning basically calls start-scan and stop-scan. In
between, it listens for dbus-signals for new peers and displays them if
they are assigned to the given link. This should be used for basic
p2p-device scanning on a link.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
This commit is contained in:
David Herrmann 2014-02-10 18:29:06 +01:00
parent 837fe1cea1
commit 44574b1d81

View file

@ -26,16 +26,120 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <locale.h> #include <locale.h>
#include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <sys/signalfd.h>
#include <systemd/sd-bus.h> #include <systemd/sd-bus.h>
#include "miracle.h" #include "miracle.h"
#include "shl_log.h" #include "shl_log.h"
#include "shl_macro.h" #include "shl_macro.h"
#include "shl_util.h" #include "shl_util.h"
/*
* Helpers for interactive commands
*/
static sd_bus *cli_bus;
static sd_event *cli_event;
static sd_event_source *cli_sigs[_NSIG];
static int cli_signal_fn(sd_event_source *source,
const struct signalfd_siginfo *ssi,
void *data)
{
if (ssi->ssi_signo == SIGCHLD) {
log_debug("caught SIGCHLD for %d", (int)ssi->ssi_pid);
return 0;
}
log_notice("caught signal %d, exiting..", (int)ssi->ssi_signo);
sd_event_exit(cli_event, 0);
return 0;
}
static void cli_destroy(void)
{
unsigned int i;
if (!cli_bus)
return;
for (i = 0; cli_sigs[i]; ++i) {
sd_event_source_unref(cli_sigs[i]);
cli_sigs[i] = NULL;
}
sd_event_unref(cli_event);
cli_event = NULL;
sd_bus_unref(cli_bus);
cli_bus = NULL;
}
static int cli_init(sd_bus *bus)
{
static const int sigs[] = {
SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGPIPE, SIGCHLD, 0
};
unsigned int i;
sigset_t mask;
int r;
if (cli_bus || !bus)
return log_EINVAL();
cli_bus = sd_bus_ref(bus);
r = sd_event_default(&cli_event);
if (r < 0) {
log_vERR(r);
goto error;
}
r = sd_bus_attach_event(cli_bus, cli_event, 0);
if (r < 0) {
log_vERR(r);
goto error;
}
for (i = 0; sigs[i]; ++i) {
sigemptyset(&mask);
sigaddset(&mask, sigs[i]);
sigprocmask(SIG_BLOCK, &mask, NULL);
r = sd_event_add_signal(cli_event,
sigs[i],
cli_signal_fn,
NULL,
&cli_sigs[i]);
if (r < 0) {
log_vERR(r);
goto error;
}
}
return 0;
error:
cli_destroy();
return r;
}
static int cli_run(void)
{
if (!cli_bus)
return log_EINVAL();
return sd_event_loop(cli_event);
}
/*
* verb: list
*/
static int verb_list_links(sd_bus *bus, sd_bus_message *m) static int verb_list_links(sd_bus *bus, sd_bus_message *m)
{ {
char *link; char *link;
@ -280,6 +384,10 @@ static int verb_list(sd_bus *bus, char **args, unsigned int n)
return 0; return 0;
} }
/*
* verb: show-link
*/
static int verb_show_link(sd_bus *bus, char **args, unsigned int n) static int verb_show_link(sd_bus *bus, char **args, unsigned int n)
{ {
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
@ -375,6 +483,10 @@ static int verb_show_link(sd_bus *bus, char **args, unsigned int n)
return 0; return 0;
} }
/*
* verb: show-peer
*/
static int verb_show_peer(sd_bus *bus, char **args, unsigned int n) static int verb_show_peer(sd_bus *bus, char **args, unsigned int n)
{ {
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
@ -503,6 +615,10 @@ static int verb_show_peer(sd_bus *bus, char **args, unsigned int n)
return 0; return 0;
} }
/*
* verb: add-link
*/
static int verb_add_link(sd_bus *bus, char **args, unsigned int n) static int verb_add_link(sd_bus *bus, char **args, unsigned int n)
{ {
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
@ -537,6 +653,10 @@ static int verb_add_link(sd_bus *bus, char **args, unsigned int n)
return 0; return 0;
} }
/*
* verb: remove-link
*/
static int verb_remove_link(sd_bus *bus, char **args, unsigned int n) static int verb_remove_link(sd_bus *bus, char **args, unsigned int n)
{ {
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
@ -560,6 +680,10 @@ static int verb_remove_link(sd_bus *bus, char **args, unsigned int n)
return 0; return 0;
} }
/*
* verb: set-link-name
*/
static int verb_set_link_name(sd_bus *bus, char **args, unsigned int n) static int verb_set_link_name(sd_bus *bus, char **args, unsigned int n)
{ {
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
@ -612,6 +736,352 @@ static int verb_set_link_name(sd_bus *bus, char **args, unsigned int n)
return 0; return 0;
} }
/*
* verb: start-scan
*/
static int verb_start_scan(sd_bus *bus, char **args, unsigned int n)
{
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
_cleanup_free_ char *path = NULL, *name = NULL;
int r;
name = sd_bus_label_escape(args[1]);
if (!name)
return log_ENOMEM();
path = shl_strcat("/org/freedesktop/miracle/link/", name);
if (!path)
return log_ENOMEM();
r = sd_bus_call_method(bus,
"org.freedesktop.miracle",
path,
"org.freedesktop.miracle.Link",
"StartScan",
&err,
NULL,
NULL);
if (r < 0) {
log_error("cannot start scan on link %s: %s",
args[1], bus_error_message(&err, r));
return r;
}
printf("Scan on link %s started\n", args[1]);
return 0;
}
/*
* verb: stop-scan
*/
static int verb_stop_scan(sd_bus *bus, char **args, unsigned int n)
{
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
_cleanup_free_ char *path = NULL, *name = NULL;
int r;
name = sd_bus_label_escape(args[1]);
if (!name)
return log_ENOMEM();
path = shl_strcat("/org/freedesktop/miracle/link/", name);
if (!path)
return log_ENOMEM();
r = sd_bus_call_method(bus,
"org.freedesktop.miracle",
path,
"org.freedesktop.miracle.Link",
"StopScan",
&err,
NULL,
NULL);
if (r < 0) {
log_error("cannot stop scan on link %s: %s",
args[1], bus_error_message(&err, r));
return r;
}
printf("Scan on link %s stopped\n", args[1]);
return 0;
}
/*
* verb: scan
*/
static int verb_scan_list_peer(sd_bus *bus,
sd_bus_message *m,
const char *link_filter,
const char *peer)
{
const char *obj, *link = NULL, *name = NULL;
int r, connected = false;
r = sd_bus_message_enter_container(m, 'a', "{sa{sv}}");
if (r < 0)
return log_bus_parser(r);
while ((r = sd_bus_message_enter_container(m,
'e',
"sa{sv}")) > 0) {
r = sd_bus_message_read(m, "s", &obj);
if (r < 0)
return log_bus_parser(r);
if (strcmp(obj, "org.freedesktop.miracle.Peer")) {
r = sd_bus_message_skip(m, "a{sv}");
if (r < 0)
return log_bus_parser(r);
r = sd_bus_message_exit_container(m);
if (r < 0)
return log_bus_parser(r);
continue;
}
r = sd_bus_message_enter_container(m, 'a', "{sv}");
if (r < 0)
return log_bus_parser(r);
while ((r = sd_bus_message_enter_container(m,
'e',
"sv")) > 0) {
r = sd_bus_message_read(m, "s", &obj);
if (r < 0)
return log_bus_parser(r);
if (!strcmp(obj, "Link")) {
r = bus_message_read_basic_variant(m, "o",
&obj);
if (r < 0)
return log_bus_parser(r);
obj = shl_startswith(obj,
"/org/freedesktop/miracle/link/");
if (obj)
link = obj;
} else if (!strcmp(obj, "Name")) {
r = bus_message_read_basic_variant(m, "s",
&name);
if (r < 0)
return log_bus_parser(r);
} else if (!strcmp(obj, "Connected")) {
r = bus_message_read_basic_variant(m, "b",
&connected);
if (r < 0)
return log_bus_parser(r);
} else {
sd_bus_message_skip(m, "v");
}
r = sd_bus_message_exit_container(m);
if (r < 0)
return log_bus_parser(r);
}
if (r < 0)
return log_bus_parser(r);
r = sd_bus_message_exit_container(m);
if (r < 0)
return log_bus_parser(r);
r = sd_bus_message_exit_container(m);
if (r < 0)
return log_bus_parser(r);
}
if (r < 0)
return log_bus_parser(r);
r = sd_bus_message_exit_container(m);
if (r < 0)
return log_bus_parser(r);
if (!strcmp(link, link_filter))
printf("%4s %-24s %-4s\n",
peer, name, connected ? "yes" : "no");
return 0;
}
static int verb_scan_list(sd_bus *bus, const char *link)
{
_cleanup_sd_bus_message_ sd_bus_message *m = NULL;
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
_cleanup_free_ char *peer = NULL;
const char *obj;
int r;
r = sd_bus_call_method(bus,
"org.freedesktop.miracle",
"/org/freedesktop/miracle",
"org.freedesktop.DBus.ObjectManager",
"GetManagedObjects",
&err,
&m,
"");
if (r < 0) {
log_error("cannot retrieve objects: %s",
bus_error_message(&err, r));
return r;
}
r = sd_bus_message_enter_container(m, 'a', "{oa{sa{sv}}}");
if (r < 0)
return log_bus_parser(r);
while ((r = sd_bus_message_enter_container(m,
'e',
"oa{sa{sv}}")) > 0) {
r = sd_bus_message_read(m, "o", &obj);
if (r < 0)
return log_bus_parser(r);
obj = shl_startswith(obj, "/org/freedesktop/miracle/peer/");
if (!obj) {
r = sd_bus_message_skip(m, "a{sa{sv}}");
if (r < 0)
return log_bus_parser(r);
r = sd_bus_message_exit_container(m);
if (r < 0)
return log_bus_parser(r);
continue;
}
free(peer);
peer = sd_bus_label_unescape(obj);
if (!peer)
return log_ENOMEM();
r = verb_scan_list_peer(bus, m, link, peer);
if (r < 0)
return r;
r = sd_bus_message_exit_container(m);
if (r < 0)
return log_bus_parser(r);
}
if (r < 0)
return log_bus_parser(r);
r = sd_bus_message_exit_container(m);
if (r < 0)
return log_bus_parser(r);
return 0;
}
static int verb_scan_match_fn(sd_bus *bus,
sd_bus_message *m,
void *data,
sd_bus_error *err)
{
_cleanup_free_ char *peer = NULL;
const char *obj, *link = data;
int r;
r = sd_bus_message_read(m, "o", &obj);
if (r < 0)
return log_bus_parser(r);
obj = shl_startswith(obj, "/org/freedesktop/miracle/peer/");
if (!obj)
return 0;
peer = sd_bus_label_unescape(obj);
if (!peer)
return log_ENOMEM();
r = verb_scan_list_peer(bus, m, link, peer);
if (r < 0)
return r;
return 0;
}
static void verb_scan_listen(sd_bus *bus, const char *link)
{
int r;
r = sd_bus_add_match(bus,
"type='signal',"
"sender='org.freedesktop.miracle',"
"interface='org.freedesktop.DBus.ObjectManager',"
"member='InterfacesAdded'",
verb_scan_match_fn,
(void*)link);
if (r < 0)
return log_error("cannot add dbus match: %d", r);
r = cli_init(bus);
if (r < 0)
goto error;
verb_scan_list(bus, link);
cli_run();
error:
cli_destroy();
sd_bus_remove_match(bus,
"type='signal',"
"sender='org.freedesktop.miracle',"
"interface='org.freedesktop.DBus.ObjectManager'",
verb_scan_match_fn,
NULL);
}
static int verb_scan(sd_bus *bus, char **args, unsigned int n)
{
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
_cleanup_free_ char *path = NULL, *name = NULL;
int r;
name = sd_bus_label_escape(args[1]);
if (!name)
return log_ENOMEM();
path = shl_strcat("/org/freedesktop/miracle/link/", name);
if (!path)
return log_ENOMEM();
r = sd_bus_call_method(bus,
"org.freedesktop.miracle",
path,
"org.freedesktop.miracle.Link",
"StartScan",
&err,
NULL,
NULL);
if (r < 0)
log_warning("cannot start scan on link %s (already running?): %s",
args[1], bus_error_message(&err, r));
printf("Scan on link %s started, listing peers..\n", args[1]);
printf("%4s %-24s %-4s\n", "ID", "NAME", "CONNECTED");
verb_scan_listen(bus, name);
r = sd_bus_call_method(bus,
"org.freedesktop.miracle",
path,
"org.freedesktop.miracle.Link",
"StopScan",
&err,
NULL,
NULL);
if (r < 0)
log_error("cannot stop scan on link %s: %s",
args[1], bus_error_message(&err, r));
else
printf("Scan on link %s stopped\n", args[1]);
return 0;
}
/*
* main
*/
static int help(void) static int help(void)
{ {
/* /*
@ -632,6 +1102,9 @@ static int help(void)
" add-link LINK... Start managing the given link\n" " add-link LINK... Start managing the given link\n"
" remove-link LINK... Stop managing the given link\n" " remove-link LINK... Stop managing the given link\n"
" set-link-name LINK NAME Set friendly-name of given link\n" " set-link-name LINK NAME Set friendly-name of given link\n"
" start-scan LINK... Start peer discovery on given link\n"
" stop-scan LINK... Stop peer discovery on given link\n"
" scan LINK... Interactive scan on given link\n"
, program_invocation_short_name); , program_invocation_short_name);
/* /*
* 80-char barrier: * 80-char barrier:
@ -696,6 +1169,9 @@ static int miraclectl_main(sd_bus *bus, int argc, char *argv[])
{ "add-link", EQUAL, 3, verb_add_link }, { "add-link", EQUAL, 3, verb_add_link },
{ "remove-link", EQUAL, 2, verb_remove_link }, { "remove-link", EQUAL, 2, verb_remove_link },
{ "set-link-name", EQUAL, 3, verb_set_link_name }, { "set-link-name", EQUAL, 3, verb_set_link_name },
{ "start-scan", EQUAL, 2, verb_start_scan },
{ "stop-scan", EQUAL, 2, verb_stop_scan },
{ "scan", EQUAL, 2, verb_scan },
}; };
int left; int left;
unsigned int i; unsigned int i;