mirror of
https://github.com/albfan/miraclecast.git
synced 2025-02-14 18:51:55 +00:00
Remove old wifi code in miracled
The wifi code is now moved to miracle-wifid, no need to keep it anymore. Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
This commit is contained in:
parent
89a268109e
commit
87b804c481
9 changed files with 24 additions and 4137 deletions
|
@ -161,11 +161,7 @@ bin_PROGRAMS += miracled
|
|||
|
||||
miracled_SOURCES = \
|
||||
src/miracled.h \
|
||||
src/miracled.c \
|
||||
src/miracled-dbus.c \
|
||||
src/miracled-link.c \
|
||||
src/miracled-peer.c \
|
||||
src/miracled-wifi.c
|
||||
src/miracled.c
|
||||
miracled_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(DEPS_CFLAGS)
|
||||
|
|
217
src/miracle.h
217
src/miracle.h
|
@ -1,217 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MIRACLE_H
|
||||
#define MIRACLE_H
|
||||
|
||||
#include <alloca.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <time.h>
|
||||
#include "shl_log.h"
|
||||
#include "shl_macro.h"
|
||||
|
||||
static inline void cleanup_sd_bus_message(sd_bus_message **ptr)
|
||||
{
|
||||
sd_bus_message_unref(*ptr);
|
||||
}
|
||||
|
||||
#define _cleanup_free_ _shl_cleanup_free_
|
||||
#define _cleanup_sd_bus_error_ _shl_cleanup_(sd_bus_error_free)
|
||||
#define _cleanup_sd_bus_message_ _shl_cleanup_(cleanup_sd_bus_message)
|
||||
|
||||
static inline const char *bus_error_message(const sd_bus_error *e, int error)
|
||||
{
|
||||
if (e) {
|
||||
if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
|
||||
return "Access denied";
|
||||
if (e->message)
|
||||
return e->message;
|
||||
}
|
||||
|
||||
return strerror(error < 0 ? -error : error);
|
||||
}
|
||||
|
||||
static inline int log_bus_parser(int r)
|
||||
{
|
||||
log_error("cannot parse dbus message: %s", strerror(r < 0 ? -r : r));
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int log_bus_create(int r)
|
||||
{
|
||||
log_error("cannot create dbus message: %s", strerror(r < 0 ? -r : r));
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int bus_message_read_basic_variant(sd_bus_message *m,
|
||||
const char *sig, void *ptr)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!sig || !*sig || sig[1] || !ptr)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'v', sig);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(m, sig, ptr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define strv_from_stdarg_alloca(first) ({ \
|
||||
char **_l; \
|
||||
if (!first) { \
|
||||
_l = (char**)&first; \
|
||||
} else { \
|
||||
unsigned _n; \
|
||||
va_list _ap; \
|
||||
_n = 1; \
|
||||
va_start(_ap, first); \
|
||||
while (va_arg(_ap, char*)) \
|
||||
_n++; \
|
||||
va_end(_ap); \
|
||||
_l = alloca(sizeof(char*) * (_n + 1)); \
|
||||
_l[_n = 0] = (char*)first; \
|
||||
va_start(_ap, first); \
|
||||
for (;;) { \
|
||||
_l[++_n] = va_arg(_ap, char*); \
|
||||
if (!_l[_n]) \
|
||||
break; \
|
||||
} \
|
||||
va_end(_ap); \
|
||||
} \
|
||||
_l; \
|
||||
})
|
||||
|
||||
static inline int64_t now(clockid_t clock_id)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
clock_gettime(clock_id, &ts);
|
||||
|
||||
return (int64_t)ts.tv_sec * 1000000LL +
|
||||
(int64_t)ts.tv_nsec / 1000LL;
|
||||
}
|
||||
|
||||
static inline char hexchar(int x)
|
||||
{
|
||||
static const char table[16] = "0123456789abcdef";
|
||||
return table[x & 15];
|
||||
}
|
||||
|
||||
static inline int unhexchar(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline char *bus_label_escape(const char *s)
|
||||
{
|
||||
char *r, *t;
|
||||
const char *f;
|
||||
|
||||
if (*s == 0)
|
||||
return strdup("_");
|
||||
|
||||
r = calloc(sizeof(char), strlen(s)*3 + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
for (f = s, t = r; *f; f++) {
|
||||
|
||||
/* Escape everything that is not a-zA-Z0-9. We also
|
||||
* escape 0-9 if it's the first character */
|
||||
|
||||
if (!(*f >= 'A' && *f <= 'Z') &&
|
||||
!(*f >= 'a' && *f <= 'z') &&
|
||||
!(f > s && *f >= '0' && *f <= '9')) {
|
||||
*(t++) = '_';
|
||||
*(t++) = hexchar(*f >> 4);
|
||||
*(t++) = hexchar(*f);
|
||||
} else
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline char *bus_label_unescape(const char *f)
|
||||
{
|
||||
char *r, *t;
|
||||
|
||||
/* Special case for the empty string */
|
||||
if (!strcmp(f, "_"))
|
||||
return strdup("");
|
||||
|
||||
r = calloc(sizeof(char), strlen(f) + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
for (t = r; *f; f++) {
|
||||
|
||||
if (*f == '_') {
|
||||
int a, b;
|
||||
|
||||
if ((a = unhexchar(f[1])) < 0 ||
|
||||
(b = unhexchar(f[2])) < 0) {
|
||||
/* Invalid escape code, let's take it literal then */
|
||||
*(t++) = '_';
|
||||
} else {
|
||||
*(t++) = (char) ((a << 4) | b);
|
||||
f += 2;
|
||||
}
|
||||
} else
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif /* MIRACLE_H */
|
|
@ -1,874 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define LOG_SUBSYSTEM "dbus"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include "miracle.h"
|
||||
#include "miracled.h"
|
||||
#include "shl_log.h"
|
||||
#include "shl_util.h"
|
||||
|
||||
/*
|
||||
* Peer DBus
|
||||
*/
|
||||
|
||||
static int peer_dbus_allow(sd_bus *bus, sd_bus_message *msg,
|
||||
void *data, sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
const char *pin;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(msg, "s", &pin);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = peer_allow(p, pin);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static int peer_dbus_reject(sd_bus *bus, sd_bus_message *msg,
|
||||
void *data, sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
|
||||
peer_reject(p);
|
||||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static int peer_dbus_connect(sd_bus *bus, sd_bus_message *msg,
|
||||
void *data, sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
const char *prov, *pin;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(msg, "ss", &prov, &pin);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = peer_connect(p, prov, pin);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static int peer_dbus_disconnect(sd_bus *bus, sd_bus_message *msg,
|
||||
void *data, sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
|
||||
peer_disconnect(p);
|
||||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static int peer_dbus_get_link(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
_shl_free_ char *link = NULL;
|
||||
struct peer *p = data;
|
||||
int r;
|
||||
|
||||
link = shl_strcat("/org/freedesktop/miracle/link/", p->l->name);
|
||||
if (!link)
|
||||
return log_ENOMEM();
|
||||
|
||||
r = sd_bus_message_append_basic(reply, 'o', link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int peer_dbus_get_name(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
name = peer_get_friendly_name(p);
|
||||
r = sd_bus_message_append_basic(reply, 's', name ? name : "<unknown>");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int peer_dbus_get_connected(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
int r, val;
|
||||
|
||||
val = peer_is_connected(p);
|
||||
r = sd_bus_message_append_basic(reply, 'b', &val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int peer_dbus_get_interface(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
const char *val;
|
||||
int r;
|
||||
|
||||
val = peer_get_interface(p);
|
||||
r = sd_bus_message_append_basic(reply, 's', val ? : "");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int peer_dbus_get_local_address(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
const char *val;
|
||||
int r;
|
||||
|
||||
val = peer_get_local_address(p);
|
||||
r = sd_bus_message_append_basic(reply, 's', val ? : "");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int peer_dbus_get_remote_address(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct peer *p = data;
|
||||
const char *val;
|
||||
int r;
|
||||
|
||||
val = peer_get_remote_address(p);
|
||||
r = sd_bus_message_append_basic(reply, 's', val ? : "");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable peer_dbus_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("Allow",
|
||||
"s",
|
||||
NULL,
|
||||
peer_dbus_allow,
|
||||
0),
|
||||
SD_BUS_METHOD("Reject",
|
||||
NULL,
|
||||
NULL,
|
||||
peer_dbus_reject,
|
||||
0),
|
||||
SD_BUS_METHOD("Connect",
|
||||
"ss",
|
||||
NULL,
|
||||
peer_dbus_connect,
|
||||
0),
|
||||
SD_BUS_METHOD("Disconnect",
|
||||
NULL,
|
||||
NULL,
|
||||
peer_dbus_disconnect,
|
||||
0),
|
||||
SD_BUS_PROPERTY("Link",
|
||||
"o",
|
||||
peer_dbus_get_link,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Name",
|
||||
"s",
|
||||
peer_dbus_get_name,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Connected",
|
||||
"b",
|
||||
peer_dbus_get_connected,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("Interface",
|
||||
"s",
|
||||
peer_dbus_get_interface,
|
||||
0,
|
||||
0),
|
||||
SD_BUS_PROPERTY("LocalAddress",
|
||||
"s",
|
||||
peer_dbus_get_local_address,
|
||||
0,
|
||||
0),
|
||||
SD_BUS_PROPERTY("RemoteAddress",
|
||||
"s",
|
||||
peer_dbus_get_remote_address,
|
||||
0,
|
||||
0),
|
||||
SD_BUS_SIGNAL("ProvisionRequest", "ss", 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
static int peer_dbus_find(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
void *data,
|
||||
void **found,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct manager *m = data;
|
||||
struct peer *p;
|
||||
const char *name;
|
||||
|
||||
if (!(name = shl_startswith(path, "/org/freedesktop/miracle/peer/")))
|
||||
return 0;
|
||||
|
||||
p = manager_find_peer(m, name);
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
*found = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void peer_dbus_provision_request(struct peer *p,
|
||||
const char *type,
|
||||
const char *pin)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
if (!type)
|
||||
return;
|
||||
if (!pin)
|
||||
pin = "";
|
||||
|
||||
path = shl_strcat("/org/freedesktop/miracle/peer/", p->name);
|
||||
if (!path)
|
||||
return log_vENOMEM();
|
||||
|
||||
r = sd_bus_emit_signal(p->l->m->bus,
|
||||
path,
|
||||
"org.freedesktop.miracle.Peer",
|
||||
"ProvisionRequest",
|
||||
"ss", type, pin);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
void peer_dbus_properties_changed(struct peer *p, const char *prop, ...)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
char **strv;
|
||||
int r;
|
||||
|
||||
path = shl_strcat("/org/freedesktop/miracle/peer/", p->name);
|
||||
if (!path)
|
||||
return log_vENOMEM();
|
||||
|
||||
strv = strv_from_stdarg_alloca(prop);
|
||||
r = sd_bus_emit_properties_changed_strv(p->l->m->bus,
|
||||
path,
|
||||
"org.freedesktop.miracle.Peer",
|
||||
strv);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
void peer_dbus_added(struct peer *p)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
path = shl_strcat("/org/freedesktop/miracle/peer/", p->name);
|
||||
if (!path)
|
||||
return log_vENOMEM();
|
||||
|
||||
r = sd_bus_emit_interfaces_added(p->l->m->bus,
|
||||
path,
|
||||
/*
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"org.freedesktop.DBus.Introspectable",
|
||||
*/
|
||||
"org.freedesktop.miracle.Peer",
|
||||
NULL);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
void peer_dbus_removed(struct peer *p)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
path = shl_strcat("/org/freedesktop/miracle/peer/", p->name);
|
||||
if (!path)
|
||||
return log_vENOMEM();
|
||||
|
||||
r = sd_bus_emit_interfaces_removed(p->l->m->bus,
|
||||
path,
|
||||
/*
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"org.freedesktop.DBus.Introspectable",
|
||||
*/
|
||||
"org.freedesktop.miracle.Peer",
|
||||
NULL);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link DBus
|
||||
*/
|
||||
|
||||
static int link_dbus_start_scan(sd_bus *bus, sd_bus_message *msg,
|
||||
void *data, sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
int r;
|
||||
|
||||
r = link_start_scan(l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static int link_dbus_stop_scan(sd_bus *bus, sd_bus_message *msg,
|
||||
void *data, sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
|
||||
link_stop_scan(l);
|
||||
|
||||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static int link_dbus_get_type(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_append_basic(reply, 's',
|
||||
link_type_to_str(l->type));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_dbus_get_interface(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_append_basic(reply, 's', l->interface);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_dbus_get_running(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
int r, val;
|
||||
|
||||
val = l->running;
|
||||
r = sd_bus_message_append_basic(reply, 'b', &val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_dbus_get_name(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_append_basic(reply, 's', l->friendly_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_dbus_set_name(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *value,
|
||||
void *data,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct link *l = data;
|
||||
int r;
|
||||
const char *name;
|
||||
|
||||
r = sd_bus_message_read(value, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return link_set_friendly_name(l, name);
|
||||
}
|
||||
|
||||
static const sd_bus_vtable link_dbus_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("StartScan",
|
||||
NULL,
|
||||
NULL,
|
||||
link_dbus_start_scan,
|
||||
0),
|
||||
SD_BUS_METHOD("StopScan",
|
||||
NULL,
|
||||
NULL,
|
||||
link_dbus_stop_scan,
|
||||
0),
|
||||
SD_BUS_PROPERTY("Type",
|
||||
"s",
|
||||
link_dbus_get_type,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Interface",
|
||||
"s",
|
||||
link_dbus_get_interface,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Running",
|
||||
"b",
|
||||
link_dbus_get_running,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_WRITABLE_PROPERTY("Name",
|
||||
"s",
|
||||
link_dbus_get_name,
|
||||
link_dbus_set_name,
|
||||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_SIGNAL("ScanStopped", NULL, 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
static int link_dbus_find(sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
void *data,
|
||||
void **found,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct manager *m = data;
|
||||
struct link *l;
|
||||
const char *name;
|
||||
|
||||
if (!(name = shl_startswith(path, "/org/freedesktop/miracle/link/")))
|
||||
return 0;
|
||||
|
||||
l = manager_find_link(m, name);
|
||||
if (!l)
|
||||
return 0;
|
||||
|
||||
*found = l;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void link_dbus_properties_changed(struct link *l, const char *prop, ...)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
char **strv;
|
||||
int r;
|
||||
|
||||
path = shl_strcat("/org/freedesktop/miracle/link/", l->name);
|
||||
if (!path)
|
||||
return log_vENOMEM();
|
||||
|
||||
strv = strv_from_stdarg_alloca(prop);
|
||||
r = sd_bus_emit_properties_changed_strv(l->m->bus,
|
||||
path,
|
||||
"org.freedesktop.miracle.Link",
|
||||
strv);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
void link_dbus_scan_stopped(struct link *l)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
path = shl_strcat("/org/freedesktop/miracle/link/", l->name);
|
||||
if (!path)
|
||||
return log_vENOMEM();
|
||||
|
||||
r = sd_bus_emit_signal(l->m->bus,
|
||||
path,
|
||||
"org.freedesktop.miracle.Link",
|
||||
"ScanStopped",
|
||||
NULL);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
void link_dbus_added(struct link *l)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
path = shl_strcat("/org/freedesktop/miracle/link/", l->name);
|
||||
if (!path)
|
||||
return log_vENOMEM();
|
||||
|
||||
r = sd_bus_emit_interfaces_added(l->m->bus,
|
||||
path,
|
||||
/*
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"org.freedesktop.DBus.Introspectable",
|
||||
*/
|
||||
"org.freedesktop.miracle.Link",
|
||||
NULL);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
void link_dbus_removed(struct link *l)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
path = shl_strcat("/org/freedesktop/miracle/link/", l->name);
|
||||
if (!path)
|
||||
return log_vENOMEM();
|
||||
|
||||
r = sd_bus_emit_interfaces_removed(l->m->bus,
|
||||
path,
|
||||
/*
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"org.freedesktop.DBus.Introspectable",
|
||||
*/
|
||||
"org.freedesktop.miracle.Link",
|
||||
NULL);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
/*
|
||||
* Manager DBus
|
||||
*/
|
||||
|
||||
static int manager_dbus_add_link(sd_bus *bus, sd_bus_message *msg,
|
||||
void *data, sd_bus_error *err)
|
||||
{
|
||||
struct manager *m = data;
|
||||
const char *stype, *interface;
|
||||
unsigned int type;
|
||||
struct link *l;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(msg, "ss", &stype, &interface);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
type = link_type_from_str(stype);
|
||||
if (type >= LINK_CNT)
|
||||
return sd_bus_error_setf(err,
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"invalid type");
|
||||
|
||||
r = link_new(m, type, interface, &l);
|
||||
if (r == -EALREADY)
|
||||
return sd_bus_error_setf(err,
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"link already available");
|
||||
else if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(msg, "s", l->name);
|
||||
}
|
||||
|
||||
static int manager_dbus_remove_link(sd_bus *bus, sd_bus_message *msg,
|
||||
void *data, sd_bus_error *err)
|
||||
{
|
||||
_shl_free_ char *link = NULL;
|
||||
struct manager *m = data;
|
||||
struct link *l;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
r = sd_bus_message_read(msg, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
link = bus_label_escape(name);
|
||||
if (!link)
|
||||
return log_ENOMEM();
|
||||
|
||||
l = manager_find_link(m, link);
|
||||
if (!l)
|
||||
return sd_bus_error_setf(err,
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"link not available");
|
||||
|
||||
link_free(l);
|
||||
|
||||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static const sd_bus_vtable manager_dbus_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("AddLink",
|
||||
"ss",
|
||||
"s",
|
||||
manager_dbus_add_link,
|
||||
0),
|
||||
SD_BUS_METHOD("RemoveLink",
|
||||
"s",
|
||||
NULL,
|
||||
manager_dbus_remove_link,
|
||||
0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
static int manager_dbus_enumerate(sd_bus *bus,
|
||||
const char *path,
|
||||
void *data,
|
||||
char ***out,
|
||||
sd_bus_error *err)
|
||||
{
|
||||
struct manager *m = data;
|
||||
struct link *l;
|
||||
struct peer *p;
|
||||
size_t i;
|
||||
char **nodes, *node;
|
||||
int r;
|
||||
|
||||
nodes = malloc(sizeof(*nodes) * (m->link_cnt + m->peer_cnt + 2));
|
||||
if (!nodes)
|
||||
return log_ENOMEM();
|
||||
|
||||
i = 0;
|
||||
MANAGER_FOREACH_LINK(l, m) {
|
||||
if (i >= m->link_cnt + m->peer_cnt) {
|
||||
log_warning("overflow: skipping link %s",
|
||||
l->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
node = shl_strcat("/org/freedesktop/miracle/link/",
|
||||
l->name);
|
||||
if (!node) {
|
||||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
|
||||
nodes[i++] = node;
|
||||
}
|
||||
|
||||
MANAGER_FOREACH_PEER(p, m) {
|
||||
if (i >= m->link_cnt + m->peer_cnt) {
|
||||
log_warning("overflow: skipping peer %s",
|
||||
p->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
node = shl_strcat("/org/freedesktop/miracle/peer/",
|
||||
p->name);
|
||||
if (!node) {
|
||||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
|
||||
nodes[i++] = node;
|
||||
}
|
||||
|
||||
node = strdup("/org/freedesktop/miracle");
|
||||
if (!node) {
|
||||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
|
||||
nodes[i++] = node;
|
||||
nodes[i] = NULL;
|
||||
*out = nodes;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
while (i--)
|
||||
free(nodes[i]);
|
||||
free(nodes);
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_dbus_connect(struct manager *m)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = sd_bus_add_object_vtable(m->bus,
|
||||
"/org/freedesktop/miracle",
|
||||
"org.freedesktop.miracle.Manager",
|
||||
manager_dbus_vtable,
|
||||
m);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_bus_add_node_enumerator(m->bus,
|
||||
"/org/freedesktop/miracle",
|
||||
manager_dbus_enumerate,
|
||||
m);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_bus_add_fallback_vtable(m->bus,
|
||||
"/org/freedesktop/miracle/link",
|
||||
"org.freedesktop.miracle.Link",
|
||||
link_dbus_vtable,
|
||||
link_dbus_find,
|
||||
m);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_bus_add_fallback_vtable(m->bus,
|
||||
"/org/freedesktop/miracle/peer",
|
||||
"org.freedesktop.miracle.Peer",
|
||||
peer_dbus_vtable,
|
||||
peer_dbus_find,
|
||||
m);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_bus_add_object_manager(m->bus, "/org/freedesktop/miracle");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_bus_request_name(m->bus, "org.freedesktop.miracle", 0);
|
||||
if (r < 0) {
|
||||
log_error("cannot claim org.freedesktop.miracle bus-name: %d",
|
||||
r);
|
||||
goto error_silent;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
log_ERR(r);
|
||||
error_silent:
|
||||
manager_dbus_disconnect(m);
|
||||
return r;
|
||||
}
|
||||
|
||||
void manager_dbus_disconnect(struct manager *m)
|
||||
{
|
||||
if (!m || !m->bus)
|
||||
return;
|
||||
|
||||
sd_bus_release_name(m->bus, "org.freedesktop.miracle");
|
||||
sd_bus_remove_object_manager(m->bus, "/org/freedesktop/miracle");
|
||||
sd_bus_remove_fallback_vtable(m->bus,
|
||||
"/org/freedesktop/miracle/peer",
|
||||
"org.freedesktop.miracle.Peer",
|
||||
peer_dbus_vtable,
|
||||
peer_dbus_find,
|
||||
m);
|
||||
sd_bus_remove_fallback_vtable(m->bus,
|
||||
"/org/freedesktop/miracle/link",
|
||||
"org.freedesktop.miracle.Link",
|
||||
link_dbus_vtable,
|
||||
link_dbus_find,
|
||||
m);
|
||||
sd_bus_remove_node_enumerator(m->bus,
|
||||
"/org/freedesktop/miracle",
|
||||
manager_dbus_enumerate,
|
||||
m);
|
||||
sd_bus_remove_object_vtable(m->bus,
|
||||
"/org/freedesktop/miracle",
|
||||
"org.freedesktop.miracle.Manager",
|
||||
manager_dbus_vtable,
|
||||
m);
|
||||
}
|
|
@ -1,429 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define LOG_SUBSYSTEM "link"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include "miracled.h"
|
||||
#include "miracled-wifi.h"
|
||||
#include "shl_dlist.h"
|
||||
#include "shl_log.h"
|
||||
#include "shl_util.h"
|
||||
|
||||
static const char *link_type_to_str_table[LINK_CNT] = {
|
||||
[LINK_VIRTUAL] = "virtual",
|
||||
[LINK_WIFI] = "wifi",
|
||||
};
|
||||
|
||||
const char *link_type_to_str(unsigned int type)
|
||||
{
|
||||
if (type >= LINK_CNT)
|
||||
return NULL;
|
||||
|
||||
return link_type_to_str_table[type];
|
||||
}
|
||||
|
||||
unsigned int link_type_from_str(const char *str)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!str)
|
||||
return LINK_CNT;
|
||||
|
||||
for (i = 0; i < LINK_CNT; ++i)
|
||||
if (link_type_to_str_table[i] &&
|
||||
!strcmp(link_type_to_str_table[i], str))
|
||||
return i;
|
||||
|
||||
return LINK_CNT;
|
||||
}
|
||||
|
||||
int link_make_name(unsigned int type, const char *interface, char **out)
|
||||
{
|
||||
const char *tname;
|
||||
char *name, *res;
|
||||
size_t tlen, ilen;
|
||||
|
||||
tname = link_type_to_str(type);
|
||||
if (!tname || !interface)
|
||||
return -EINVAL;
|
||||
|
||||
/* hard-coded maximum of 255 just to be safe */
|
||||
tlen = strlen(tname);
|
||||
ilen = strlen(interface);
|
||||
if (!tlen || tlen > 255 || !ilen || ilen > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (!out)
|
||||
return 0;
|
||||
|
||||
name = shl_strjoin(tname, ":", interface, NULL);
|
||||
if (!name)
|
||||
return log_ENOMEM();
|
||||
|
||||
res = bus_label_escape(name);
|
||||
free(name);
|
||||
if (!res)
|
||||
return log_ENOMEM();
|
||||
|
||||
*out = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wifi Handling
|
||||
*/
|
||||
|
||||
static void link_wifi_event_fn(struct wifi *w, void *data,
|
||||
struct wifi_event *ev)
|
||||
{
|
||||
struct link *l = data;
|
||||
struct peer *p;
|
||||
|
||||
switch (ev->type) {
|
||||
case WIFI_HUP:
|
||||
/* destroy this link */
|
||||
link_free(l);
|
||||
break;
|
||||
case WIFI_SCAN_STOPPED:
|
||||
link_dbus_scan_stopped(l);
|
||||
break;
|
||||
case WIFI_DEV_FOUND:
|
||||
peer_new_wifi(l, ev->dev_found.dev, NULL);
|
||||
break;
|
||||
case WIFI_DEV_LOST:
|
||||
p = wifi_dev_get_data(ev->dev_lost.dev);
|
||||
if (!p)
|
||||
break;
|
||||
|
||||
peer_free(p);
|
||||
break;
|
||||
case WIFI_DEV_PROVISION:
|
||||
case WIFI_DEV_CONNECT:
|
||||
case WIFI_DEV_DISCONNECT:
|
||||
p = wifi_dev_get_data(ev->dev_lost.dev);
|
||||
if (!p)
|
||||
break;
|
||||
|
||||
peer_process_wifi(p, ev);
|
||||
break;
|
||||
default:
|
||||
log_debug("unhandled WIFI event: %u", ev->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int link_wifi_start(struct link *l)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
struct wifi_dev *d;
|
||||
int r;
|
||||
|
||||
path = shl_strjoin(arg_wpa_rundir, "/", l->interface, NULL);
|
||||
if (!path)
|
||||
return log_ENOMEM();
|
||||
|
||||
r = wifi_open(l->w, path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = wifi_set_name(l->w, l->friendly_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (d = wifi_get_devs(l->w); d; d = wifi_dev_next(d))
|
||||
peer_new_wifi(l, d, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_wifi_child_fn(sd_event_source *source,
|
||||
const siginfo_t *si,
|
||||
void *data)
|
||||
{
|
||||
struct link *l = data;
|
||||
|
||||
log_error("wpa_supplicant died unexpectedly on link %s", l->name);
|
||||
|
||||
link_free(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_wifi_startup_fn(sd_event_source *source,
|
||||
uint64_t usec,
|
||||
void *data)
|
||||
{
|
||||
struct link *l = data;
|
||||
int r;
|
||||
|
||||
r = link_wifi_start(l);
|
||||
if (r < 0) {
|
||||
if (wifi_is_open(l->w) || ++l->wpa_startup_attempts >= 5) {
|
||||
log_error("cannot start wifi on link %s", l->name);
|
||||
link_free(l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reschedule timer */
|
||||
sd_event_source_set_time(source,
|
||||
now(CLOCK_MONOTONIC) + 200 * 1000);
|
||||
sd_event_source_set_enabled(source, SD_EVENT_ON);
|
||||
log_debug("wpa_supplicant startup still ongoing, reschedule..");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("wpa_supplicant startup finished on link %s", l->name);
|
||||
|
||||
sd_event_source_set_enabled(source, SD_EVENT_OFF);
|
||||
l->running = true;
|
||||
link_dbus_properties_changed(l, "Running", NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_wifi_init(struct link *l)
|
||||
{
|
||||
_shl_free_ char *path = NULL;
|
||||
int r;
|
||||
|
||||
r = wifi_new(l->m->event, link_wifi_event_fn, l, &l->w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!arg_manage_wifi) {
|
||||
r = link_wifi_start(l);
|
||||
if (r < 0)
|
||||
log_error("cannot open wpa_supplicant socket for link %s",
|
||||
l->name);
|
||||
else
|
||||
l->running = true;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
path = shl_strcat(arg_wpa_bindir, "/wpa_supplicant");
|
||||
if (!path)
|
||||
return log_ENOMEM();
|
||||
|
||||
r = wifi_spawn_supplicant(l->w, arg_wpa_rundir, path, l->interface);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_add_child(l->m->event,
|
||||
&l->wpa_child_source,
|
||||
wifi_get_supplicant_pid(l->w),
|
||||
WEXITED,
|
||||
link_wifi_child_fn,
|
||||
l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_add_monotonic(l->m->event,
|
||||
&l->wpa_startup_source,
|
||||
now(CLOCK_MONOTONIC) + 200 * 1000,
|
||||
0,
|
||||
link_wifi_startup_fn,
|
||||
l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void link_wifi_destroy(struct link *l)
|
||||
{
|
||||
sd_event_source_unref(l->wpa_startup_source);
|
||||
sd_event_source_unref(l->wpa_child_source);
|
||||
wifi_close(l->w);
|
||||
wifi_free(l->w);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link Handling
|
||||
*/
|
||||
|
||||
int link_new(struct manager *m,
|
||||
unsigned int type,
|
||||
const char *interface,
|
||||
struct link **out)
|
||||
{
|
||||
size_t hash = 0;
|
||||
char *name;
|
||||
struct link *l;
|
||||
int r;
|
||||
|
||||
if (!m)
|
||||
return log_EINVAL();
|
||||
|
||||
r = link_make_name(type, interface, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (shl_htable_lookup_str(&m->links, name, &hash, NULL)) {
|
||||
free(name);
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
log_debug("new link: %s", name);
|
||||
|
||||
l = calloc(1, sizeof(*l));
|
||||
if (!l) {
|
||||
free(name);
|
||||
return log_ENOMEM();
|
||||
}
|
||||
|
||||
l->m = m;
|
||||
l->type = type;
|
||||
l->name = name;
|
||||
shl_dlist_init(&l->peers);
|
||||
|
||||
l->interface = strdup(interface);
|
||||
if (!l->interface) {
|
||||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
|
||||
l->friendly_name = strdup(m->friendly_name);
|
||||
if (!l->friendly_name) {
|
||||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (l->type) {
|
||||
case LINK_VIRTUAL:
|
||||
l->running = true;
|
||||
break;
|
||||
case LINK_WIFI:
|
||||
r = link_wifi_init(l);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
|
||||
r = shl_htable_insert_str(&m->links, &l->name, &hash);
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
++m->link_cnt;
|
||||
link_dbus_added(l);
|
||||
log_info("new managed link: %s", l->name);
|
||||
|
||||
if (out)
|
||||
*out = l;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
link_free(l);
|
||||
return r;
|
||||
}
|
||||
|
||||
void link_free(struct link *l)
|
||||
{
|
||||
struct peer *p;
|
||||
|
||||
if (!l)
|
||||
return;
|
||||
|
||||
log_debug("free link: %s", l->name);
|
||||
|
||||
while ((p = LINK_FIRST_PEER(l)))
|
||||
peer_free(p);
|
||||
|
||||
if (shl_htable_remove_str(&l->m->links, l->name, NULL, NULL)) {
|
||||
log_info("remove managed link: %s", l->name);
|
||||
link_dbus_removed(l);
|
||||
--l->m->link_cnt;
|
||||
}
|
||||
|
||||
link_wifi_destroy(l);
|
||||
free(l->friendly_name);
|
||||
free(l->name);
|
||||
free(l->interface);
|
||||
free(l);
|
||||
}
|
||||
|
||||
int link_set_friendly_name(struct link *l, const char *name)
|
||||
{
|
||||
char *dup;
|
||||
int r;
|
||||
|
||||
if (!l || !name)
|
||||
return log_EINVAL();
|
||||
|
||||
dup = strdup(name);
|
||||
if (!dup)
|
||||
return log_ENOMEM();
|
||||
|
||||
r = 0;
|
||||
switch (l->type) {
|
||||
case LINK_WIFI:
|
||||
r = wifi_set_name(l->w, name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
free(dup);
|
||||
return r;
|
||||
}
|
||||
|
||||
free(l->friendly_name);
|
||||
l->friendly_name = dup;
|
||||
link_dbus_properties_changed(l, "Name", NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_start_scan(struct link *l)
|
||||
{
|
||||
if (!l)
|
||||
return -EINVAL;
|
||||
|
||||
switch (l->type) {
|
||||
case LINK_VIRTUAL:
|
||||
return -EOPNOTSUPP;
|
||||
case LINK_WIFI:
|
||||
return wifi_set_discoverable(l->w, true);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void link_stop_scan(struct link *l)
|
||||
{
|
||||
if (!l)
|
||||
return;
|
||||
|
||||
switch (l->type) {
|
||||
case LINK_WIFI:
|
||||
wifi_set_discoverable(l->w, false);
|
||||
}
|
||||
}
|
|
@ -1,305 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define LOG_SUBSYSTEM "peer"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include "miracled.h"
|
||||
#include "miracled-wifi.h"
|
||||
#include "shl_log.h"
|
||||
|
||||
int peer_make_name(unsigned int id, char **out)
|
||||
{
|
||||
char buf[64] = { };
|
||||
char *name;
|
||||
|
||||
if (!out)
|
||||
return 0;
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "%u", id);
|
||||
name = bus_label_escape(buf);
|
||||
if (!name)
|
||||
return log_ENOMEM();
|
||||
|
||||
*out = name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int peer_new(struct link *l, struct peer **out)
|
||||
{
|
||||
unsigned int id;
|
||||
char *name;
|
||||
struct peer *p;
|
||||
int r;
|
||||
|
||||
if (!l)
|
||||
return log_EINVAL();
|
||||
|
||||
id = ++l->m->peer_ids;
|
||||
r = peer_make_name(id, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (shl_htable_lookup_str(&l->m->peers, name, NULL, NULL)) {
|
||||
free(name);
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
log_debug("new peer: %s", name);
|
||||
|
||||
p = calloc(1, sizeof(*p));
|
||||
if (!p) {
|
||||
free(name);
|
||||
return log_ENOMEM();
|
||||
}
|
||||
|
||||
p->l = l;
|
||||
p->id = id;
|
||||
p->name = name;
|
||||
|
||||
if (out)
|
||||
*out = p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int peer_link(struct peer *p)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = shl_htable_insert_str(&p->l->m->peers, &p->name, NULL);
|
||||
if (r < 0)
|
||||
return log_ERR(r);
|
||||
|
||||
++p->l->m->peer_cnt;
|
||||
shl_dlist_link(&p->l->peers, &p->list);
|
||||
peer_dbus_added(p);
|
||||
log_info("new peer: %s@%s", p->name, p->l->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int peer_new_wifi(struct link *l, struct wifi_dev *d, struct peer **out)
|
||||
{
|
||||
int r;
|
||||
struct peer *p;
|
||||
|
||||
r = peer_new(l, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p->d = d;
|
||||
wifi_dev_set_data(p->d, p);
|
||||
|
||||
r = peer_link(p);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (out)
|
||||
*out = p;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
peer_free(p);
|
||||
return r;
|
||||
}
|
||||
|
||||
void peer_free(struct peer *p)
|
||||
{
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
log_debug("free peer: %s", p->name);
|
||||
|
||||
if (shl_htable_remove_str(&p->l->m->peers, p->name, NULL, NULL)) {
|
||||
log_info("remove managed peer: %s@%s", p->name, p->l->name);
|
||||
peer_dbus_removed(p);
|
||||
--p->l->m->peer_cnt;
|
||||
shl_dlist_unlink(&p->list);
|
||||
}
|
||||
|
||||
wifi_dev_set_data(p->d, NULL);
|
||||
|
||||
free(p->name);
|
||||
free(p);
|
||||
}
|
||||
|
||||
const char *peer_get_friendly_name(struct peer *p)
|
||||
{
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (p->d)
|
||||
return wifi_dev_get_name(p->d);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool peer_is_connected(struct peer *p)
|
||||
{
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
if (p->d)
|
||||
return wifi_dev_is_ready(p->d);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *peer_get_interface(struct peer *p)
|
||||
{
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (p->d)
|
||||
return wifi_dev_get_interface(p->d);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *peer_get_local_address(struct peer *p)
|
||||
{
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (p->d)
|
||||
return wifi_dev_get_local_address(p->d);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *peer_get_remote_address(struct peer *p)
|
||||
{
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (p->d)
|
||||
return wifi_dev_get_remote_address(p->d);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *peer_provision_str[WIFI_PROVISION_CNT] = {
|
||||
[WIFI_PROVISION_PBC] = "pbc",
|
||||
[WIFI_PROVISION_DISPLAY] = "display",
|
||||
[WIFI_PROVISION_PIN] = "pin",
|
||||
};
|
||||
|
||||
static const char *peer_provision_to_str(unsigned int prov)
|
||||
{
|
||||
if (prov >= WIFI_PROVISION_CNT)
|
||||
return NULL;
|
||||
|
||||
return peer_provision_str[prov];
|
||||
}
|
||||
|
||||
static unsigned int peer_provision_from_str(const char *prov)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!prov || !*prov)
|
||||
return WIFI_PROVISION_CNT;
|
||||
|
||||
for (i = 0; i < WIFI_PROVISION_CNT; ++i)
|
||||
if (peer_provision_str[i])
|
||||
if (!strcmp(prov, peer_provision_str[i]))
|
||||
return i;
|
||||
|
||||
return WIFI_PROVISION_CNT;
|
||||
}
|
||||
|
||||
void peer_process_wifi(struct peer *p, struct wifi_event *ev)
|
||||
{
|
||||
const char *prov;
|
||||
|
||||
if (!p || !p->d)
|
||||
return;
|
||||
|
||||
switch (ev->type) {
|
||||
case WIFI_DEV_PROVISION:
|
||||
prov = peer_provision_to_str(ev->dev_provision.type);
|
||||
if (!prov)
|
||||
break;
|
||||
|
||||
peer_dbus_provision_request(p, prov, ev->dev_provision.pin);
|
||||
break;
|
||||
case WIFI_DEV_CONNECT:
|
||||
peer_dbus_properties_changed(p, "Connected", NULL);
|
||||
break;
|
||||
case WIFI_DEV_DISCONNECT:
|
||||
peer_dbus_properties_changed(p, "Connected", NULL);
|
||||
break;
|
||||
default:
|
||||
log_debug("unhandled WIFI event: %u", ev->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int peer_allow(struct peer *p, const char *pin)
|
||||
{
|
||||
if (!p || !p->d)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
wifi_dev_allow(p->d, pin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void peer_reject(struct peer *p)
|
||||
{
|
||||
if (!p || !p->d)
|
||||
return;
|
||||
|
||||
wifi_dev_reject(p->d);
|
||||
}
|
||||
|
||||
int peer_connect(struct peer *p, const char *prov, const char *pin)
|
||||
{
|
||||
if (!p || !p->d)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!prov)
|
||||
prov = "";
|
||||
if (!pin)
|
||||
pin = "";
|
||||
|
||||
return wifi_dev_connect(p->d, peer_provision_from_str(prov), pin);
|
||||
}
|
||||
|
||||
void peer_disconnect(struct peer *p)
|
||||
{
|
||||
bool change;
|
||||
|
||||
if (!p || !p->d)
|
||||
return;
|
||||
|
||||
change = peer_is_connected(p);
|
||||
wifi_dev_disconnect(p->d);
|
||||
if (change)
|
||||
peer_dbus_properties_changed(p, "Connected", NULL);
|
||||
}
|
1623
src/miracled-wifi.c
1623
src/miracled-wifi.c
File diff suppressed because it is too large
Load diff
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include "miracle.h"
|
||||
|
||||
#ifndef MIRACLED_WIFI_H
|
||||
#define MIRACLED_WIFI_H
|
||||
|
||||
struct wifi;
|
||||
struct wifi_dev;
|
||||
|
||||
/* wifi */
|
||||
|
||||
struct wifi;
|
||||
struct wifi_dev;
|
||||
|
||||
enum wifi_event_type {
|
||||
WIFI_HUP,
|
||||
WIFI_SCAN_STOPPED,
|
||||
WIFI_DEV_FOUND,
|
||||
WIFI_DEV_LOST,
|
||||
WIFI_DEV_PROVISION,
|
||||
WIFI_DEV_CONNECT,
|
||||
WIFI_DEV_DISCONNECT,
|
||||
};
|
||||
|
||||
enum wifi_provision_type {
|
||||
WIFI_PROVISION_PBC,
|
||||
WIFI_PROVISION_DISPLAY,
|
||||
WIFI_PROVISION_PIN,
|
||||
WIFI_PROVISION_CNT,
|
||||
};
|
||||
|
||||
/* WPS pins are fixed to 8 chars (+1 terminating zero) */
|
||||
#define WIFI_PIN_STRLEN (8 + 1)
|
||||
|
||||
struct wifi_event {
|
||||
unsigned int type;
|
||||
|
||||
union {
|
||||
struct wifi_event_dev_found {
|
||||
struct wifi_dev *dev;
|
||||
} dev_found;
|
||||
|
||||
struct wifi_event_dev_lost {
|
||||
struct wifi_dev *dev;
|
||||
} dev_lost;
|
||||
|
||||
struct wifi_event_dev_provision {
|
||||
struct wifi_dev *dev;
|
||||
unsigned int type;
|
||||
char pin[WIFI_PIN_STRLEN];
|
||||
} dev_provision;
|
||||
|
||||
struct wifi_event_dev_connect {
|
||||
struct wifi_dev *dev;
|
||||
} dev_connect;
|
||||
|
||||
struct wifi_event_dev_disconnect {
|
||||
struct wifi_dev *dev;
|
||||
} dev_disconnect;
|
||||
};
|
||||
};
|
||||
|
||||
typedef void (*wifi_event_t) (struct wifi *w, void *data,
|
||||
struct wifi_event *ev);
|
||||
|
||||
int wifi_new(sd_event *event, wifi_event_t event_fn, void *data,
|
||||
struct wifi **out);
|
||||
void wifi_free(struct wifi *w);
|
||||
void wifi_set_data(struct wifi *w, void *data);
|
||||
void *wifi_get_data(struct wifi *w);
|
||||
|
||||
pid_t wifi_get_supplicant_pid(struct wifi *w);
|
||||
int wifi_spawn_supplicant(struct wifi *w,
|
||||
const char *rundir,
|
||||
const char *binary,
|
||||
const char *ifname);
|
||||
|
||||
bool wifi_is_open(struct wifi *w);
|
||||
int wifi_open(struct wifi *w, const char *wpa_path);
|
||||
void wifi_close(struct wifi *w);
|
||||
|
||||
int wifi_set_discoverable(struct wifi *w, bool on);
|
||||
int wifi_set_name(struct wifi *w, const char *name);
|
||||
|
||||
struct wifi_dev *wifi_get_devs(struct wifi *w);
|
||||
struct wifi_dev *wifi_dev_next(struct wifi_dev *d);
|
||||
|
||||
/* wifi device */
|
||||
|
||||
void wifi_dev_ref(struct wifi_dev *d);
|
||||
void wifi_dev_unref(struct wifi_dev *d);
|
||||
void wifi_dev_set_data(struct wifi_dev *d, void *data);
|
||||
void *wifi_dev_get_data(struct wifi_dev *d);
|
||||
|
||||
bool wifi_dev_is_available(struct wifi_dev *d);
|
||||
bool wifi_dev_is_running(struct wifi_dev *d);
|
||||
bool wifi_dev_is_ready(struct wifi_dev *d);
|
||||
|
||||
void wifi_dev_allow(struct wifi_dev *d, const char *pin);
|
||||
void wifi_dev_reject(struct wifi_dev *d);
|
||||
int wifi_dev_connect(struct wifi_dev *d, unsigned int provision,
|
||||
const char *pin);
|
||||
void wifi_dev_disconnect(struct wifi_dev *d);
|
||||
|
||||
const char *wifi_dev_get_name(struct wifi_dev *d);
|
||||
const char *wifi_dev_get_interface(struct wifi_dev *d);
|
||||
const char *wifi_dev_get_local_address(struct wifi_dev *d);
|
||||
const char *wifi_dev_get_remote_address(struct wifi_dev *d);
|
||||
|
||||
#endif /* MIRACLED_WIFI_H */
|
404
src/miracled.c
404
src/miracled.c
|
@ -3,30 +3,22 @@
|
|||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
* MiracleCast is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
* MiracleCast is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libudev.h>
|
||||
#include <libwfd.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
@ -39,373 +31,26 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "miracled.h"
|
||||
#include "shl_htable.h"
|
||||
#include "shl_macro.h"
|
||||
#include "shl_log.h"
|
||||
#include "shl_util.h"
|
||||
|
||||
bool arg_manage_wifi = false;
|
||||
const char *arg_wpa_rundir = "/run/wpa_supplicant";
|
||||
const char *arg_wpa_bindir = "/usr/bin";
|
||||
|
||||
/*
|
||||
* Peer Handling
|
||||
*/
|
||||
|
||||
struct peer *manager_find_peer(struct manager *m, const char *name)
|
||||
{
|
||||
char **elem;
|
||||
bool res;
|
||||
|
||||
res = shl_htable_lookup_str(&m->peers, name, NULL, &elem);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
return peer_from_htable(elem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link Handling
|
||||
*/
|
||||
|
||||
struct link *manager_find_link(struct manager *m, const char *name)
|
||||
{
|
||||
char **elem;
|
||||
bool res;
|
||||
|
||||
res = shl_htable_lookup_str(&m->links, name, NULL, &elem);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
return link_from_htable(elem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Manager Handling
|
||||
*/
|
||||
|
||||
static void manager_add_link_from_udev(struct manager *m,
|
||||
struct udev_device *d)
|
||||
{
|
||||
struct link *l;
|
||||
|
||||
if (!udev_device_has_tag(d, "miracle"))
|
||||
return;
|
||||
|
||||
log_debug("link %s tagged via udev",
|
||||
udev_device_get_sysname(d));
|
||||
|
||||
link_new(m,
|
||||
LINK_WIFI,
|
||||
udev_device_get_sysname(d),
|
||||
&l);
|
||||
}
|
||||
|
||||
static void manager_remove_link_from_udev(struct manager *m,
|
||||
struct udev_device *d)
|
||||
{
|
||||
_shl_free_ char *name = NULL;
|
||||
int r;
|
||||
struct link *l;
|
||||
|
||||
r = link_make_name(LINK_WIFI, udev_device_get_sysname(d), &name);
|
||||
if (r < 0)
|
||||
return log_vERR(r);
|
||||
|
||||
l = manager_find_link(m, name);
|
||||
if (!l)
|
||||
return;
|
||||
|
||||
log_debug("link %s removed via udev", name);
|
||||
|
||||
link_free(l);
|
||||
}
|
||||
|
||||
static int manager_udev_fn(sd_event_source *source,
|
||||
int fd,
|
||||
uint32_t mask,
|
||||
void *data)
|
||||
{
|
||||
struct manager *m = data;
|
||||
struct udev_device *d = NULL;
|
||||
const char *action;
|
||||
|
||||
d = udev_monitor_receive_device(m->udev_mon);
|
||||
if (!d)
|
||||
goto out;
|
||||
|
||||
action = udev_device_get_action(d);
|
||||
if (!action)
|
||||
goto out;
|
||||
|
||||
if (!strcmp(action, "add") && arg_manage_wifi)
|
||||
manager_add_link_from_udev(m, d);
|
||||
else if (!strcmp(action, "remove"))
|
||||
manager_remove_link_from_udev(m, d);
|
||||
|
||||
out:
|
||||
udev_device_unref(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_signal_fn(sd_event_source *source,
|
||||
const struct signalfd_siginfo *ssi,
|
||||
void *data)
|
||||
{
|
||||
struct manager *m = 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(m->event, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void manager_free(struct manager *m)
|
||||
{
|
||||
unsigned int i;
|
||||
struct link *l;
|
||||
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
while ((l = MANAGER_FIRST_LINK(m)))
|
||||
link_free(l);
|
||||
|
||||
shl_htable_clear_str(&m->links, NULL, NULL);
|
||||
shl_htable_clear_str(&m->peers, NULL, NULL);
|
||||
|
||||
manager_dbus_disconnect(m);
|
||||
|
||||
sd_event_source_unref(m->udev_mon_source);
|
||||
udev_monitor_unref(m->udev_mon);
|
||||
udev_unref(m->udev);
|
||||
|
||||
for (i = 0; m->sigs[i]; ++i)
|
||||
sd_event_source_unref(m->sigs[i]);
|
||||
sd_bus_unref(m->bus);
|
||||
sd_event_unref(m->event);
|
||||
free(m->friendly_name);
|
||||
free(m);
|
||||
}
|
||||
|
||||
static int manager_new(struct manager **out)
|
||||
{
|
||||
char buf[64] = { };
|
||||
struct manager *m;
|
||||
static const int sigs[] = {
|
||||
SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGPIPE, SIGCHLD, 0
|
||||
};
|
||||
unsigned int i;
|
||||
sigset_t mask;
|
||||
int r;
|
||||
|
||||
m = calloc(1, sizeof(*m));
|
||||
if (!m)
|
||||
return log_ENOMEM();
|
||||
|
||||
shl_htable_init_str(&m->links);
|
||||
shl_htable_init_str(&m->peers);
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "unknown-%u", rand());
|
||||
m->friendly_name = strdup(buf);
|
||||
if (!m->friendly_name) {
|
||||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_event_default(&m->event);
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_event_set_watchdog(m->event, true);
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_bus_default_system(&m->bus);
|
||||
if (r < 0) {
|
||||
log_error("cannot connect to system bus: %d", r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_bus_attach_event(m->bus, m->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(m->event,
|
||||
&m->sigs[i],
|
||||
sigs[i],
|
||||
manager_signal_fn,
|
||||
m);
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
m->udev = udev_new();
|
||||
if (!m->udev) {
|
||||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
|
||||
m->udev_mon = udev_monitor_new_from_netlink(m->udev, "udev");
|
||||
if (!m->udev_mon) {
|
||||
r = log_ENOMEM();
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_mon,
|
||||
"net",
|
||||
"wlan");
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = udev_monitor_enable_receiving(m->udev_mon);
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_event_add_io(m->event,
|
||||
&m->udev_mon_source,
|
||||
udev_monitor_get_fd(m->udev_mon),
|
||||
EPOLLHUP | EPOLLERR | EPOLLIN,
|
||||
manager_udev_fn,
|
||||
m);
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = manager_dbus_connect(m);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
*out = m;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
manager_free(m);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void manager_read_name(struct manager *m)
|
||||
{
|
||||
_cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL;
|
||||
_cleanup_sd_bus_message_ sd_bus_message *rep = NULL;
|
||||
const char *name;
|
||||
char *str;
|
||||
int r;
|
||||
|
||||
r = sd_bus_call_method(m->bus,
|
||||
"org.freedesktop.hostname1",
|
||||
"/org/freedesktop/hostname1",
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"Get",
|
||||
&err,
|
||||
&rep,
|
||||
"ss", "org.freedesktop.hostname1", "Hostname");
|
||||
if (r < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(rep, 'v', "s");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_bus_message_read(rep, "s", &name);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (!name || !*name) {
|
||||
log_warning("no hostname set on systemd.hostname1, using: %s",
|
||||
m->friendly_name);
|
||||
return;
|
||||
}
|
||||
|
||||
str = strdup(name);
|
||||
if (!str)
|
||||
return log_vENOMEM();
|
||||
|
||||
free(m->friendly_name);
|
||||
m->friendly_name = str;
|
||||
log_debug("friendly-name from local hostname: %s", str);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
log_warning("cannot read hostname from systemd.hostname1: %s",
|
||||
bus_error_message(&err, r));
|
||||
}
|
||||
|
||||
static void manager_read_links(struct manager *m)
|
||||
{
|
||||
struct udev_enumerate *e = NULL;
|
||||
struct udev_list_entry *l;
|
||||
struct udev_device *d;
|
||||
int r;
|
||||
|
||||
e = udev_enumerate_new(m->udev);
|
||||
if (!e)
|
||||
goto error;
|
||||
|
||||
r = udev_enumerate_add_match_subsystem(e, "net");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = udev_enumerate_add_match_property(e, "DEVTYPE", "wlan");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = udev_enumerate_add_match_is_initialized(e);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = udev_enumerate_scan_devices(e);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
udev_list_entry_foreach(l, udev_enumerate_get_list_entry(e)) {
|
||||
d = udev_device_new_from_syspath(m->udev,
|
||||
udev_list_entry_get_name(l));
|
||||
if (!d)
|
||||
goto error;
|
||||
|
||||
manager_add_link_from_udev(m, d);
|
||||
udev_device_unref(d);
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
error:
|
||||
log_warning("cannot enumerate links via udev");
|
||||
out:
|
||||
udev_enumerate_unref(e);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int manager_run(struct manager *m)
|
||||
{
|
||||
manager_read_name(m);
|
||||
manager_read_links(m);
|
||||
return sd_event_loop(m->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int help(void)
|
||||
|
@ -415,16 +60,11 @@ static int help(void)
|
|||
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||
*/
|
||||
printf("%s [OPTIONS...] ...\n\n"
|
||||
"Wifi-Display Daemon.\n\n"
|
||||
"Remote-display Management-daemon.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" --log-time Prefix log-messages with timestamp\n"
|
||||
"\n"
|
||||
" --manage-wifi Enable internal wifi-management via wpa_supplicant if\n"
|
||||
" they're not managed externally (like NetworkManager)\n"
|
||||
" --wpa-rundir <dir> wpa_supplicant runtime dir [/run/wpa_supplicant]\n"
|
||||
" --wpa-bindir <dir> wpa_supplicant binary dir [/usr/bin]\n"
|
||||
, program_invocation_short_name);
|
||||
/*
|
||||
* 80-char barrier:
|
||||
|
@ -440,20 +80,12 @@ static int parse_argv(int argc, char *argv[])
|
|||
ARG_VERSION = 0x100,
|
||||
ARG_LOG_LEVEL,
|
||||
ARG_LOG_TIME,
|
||||
|
||||
ARG_MANAGE_WIFI,
|
||||
ARG_WPA_RUNDIR,
|
||||
ARG_WPA_BINDIR,
|
||||
};
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "log-time", no_argument, NULL, ARG_LOG_TIME },
|
||||
|
||||
{ "manage-wifi", no_argument, NULL, ARG_MANAGE_WIFI },
|
||||
{ "wpa-rundir", required_argument, NULL, ARG_WPA_RUNDIR },
|
||||
{ "wpa-bindir", required_argument, NULL, ARG_WPA_BINDIR },
|
||||
{}
|
||||
};
|
||||
int c;
|
||||
|
@ -471,16 +103,6 @@ static int parse_argv(int argc, char *argv[])
|
|||
case ARG_LOG_TIME:
|
||||
log_init_time();
|
||||
break;
|
||||
|
||||
case ARG_MANAGE_WIFI:
|
||||
arg_manage_wifi = true;
|
||||
break;
|
||||
case ARG_WPA_RUNDIR:
|
||||
arg_wpa_rundir = optarg;
|
||||
break;
|
||||
case ARG_WPA_BINDIR:
|
||||
arg_wpa_bindir = optarg;
|
||||
break;
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
165
src/miracled.h
165
src/miracled.h
|
@ -3,178 +3,33 @@
|
|||
*
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
* MiracleCast is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
* MiracleCast is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <libudev.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <systemd/sd-event.h>
|
||||
#include "miracle.h"
|
||||
#include "shl_dlist.h"
|
||||
#include "shl_htable.h"
|
||||
|
||||
#ifndef MIRACLED_H
|
||||
#define MIRACLED_H
|
||||
|
||||
struct manager;
|
||||
struct link;
|
||||
struct peer;
|
||||
struct wifi;
|
||||
struct wifi_dev;
|
||||
struct wifi_event;
|
||||
|
||||
/* peer */
|
||||
|
||||
struct peer {
|
||||
struct shl_dlist list;
|
||||
struct link *l;
|
||||
unsigned int id;
|
||||
char *name;
|
||||
|
||||
struct wifi_dev *d;
|
||||
};
|
||||
|
||||
#define peer_from_htable(_p) \
|
||||
shl_htable_offsetof((_p), struct peer, name)
|
||||
#define peer_from_list(_p) \
|
||||
shl_dlist_entry((_p), struct peer, list)
|
||||
|
||||
int peer_make_name(unsigned int id, char **out);
|
||||
|
||||
int peer_new_wifi(struct link *l, struct wifi_dev *d, struct peer **out);
|
||||
void peer_free(struct peer *p);
|
||||
|
||||
const char *peer_get_friendly_name(struct peer *p);
|
||||
bool peer_is_connected(struct peer *p);
|
||||
const char *peer_get_interface(struct peer *p);
|
||||
const char *peer_get_local_address(struct peer *p);
|
||||
const char *peer_get_remote_address(struct peer *p);
|
||||
|
||||
void peer_process_wifi(struct peer *p, struct wifi_event *ev);
|
||||
|
||||
int peer_allow(struct peer *p, const char *pin);
|
||||
void peer_reject(struct peer *p);
|
||||
int peer_connect(struct peer *p, const char *prov, const char *pin);
|
||||
void peer_disconnect(struct peer *p);
|
||||
|
||||
/* link */
|
||||
|
||||
enum link_type {
|
||||
LINK_VIRTUAL,
|
||||
LINK_WIFI,
|
||||
LINK_CNT,
|
||||
};
|
||||
|
||||
struct link {
|
||||
struct manager *m;
|
||||
unsigned int type;
|
||||
char *interface;
|
||||
char *name;
|
||||
char *friendly_name;
|
||||
|
||||
struct shl_dlist peers;
|
||||
|
||||
struct wifi *w;
|
||||
sd_event_source *wpa_child_source;
|
||||
sd_event_source *wpa_startup_source;
|
||||
unsigned int wpa_startup_attempts;
|
||||
|
||||
bool running : 1;
|
||||
};
|
||||
|
||||
#define link_from_htable(_l) \
|
||||
shl_htable_offsetof((_l), struct link, name)
|
||||
#define LINK_FIRST_PEER(_l) (shl_dlist_empty(&(_l)->peers) ? \
|
||||
NULL : peer_from_list((_l)->peers.next))
|
||||
|
||||
const char *link_type_to_str(unsigned int type);
|
||||
unsigned int link_type_from_str(const char *str);
|
||||
int link_make_name(unsigned int type, const char *interface, char **out);
|
||||
|
||||
int link_new(struct manager *m,
|
||||
unsigned int type,
|
||||
const char *interface,
|
||||
struct link **out);
|
||||
void link_free(struct link *l);
|
||||
|
||||
int link_set_friendly_name(struct link *l, const char *name);
|
||||
|
||||
int link_start_scan(struct link *l);
|
||||
void link_stop_scan(struct link *l);
|
||||
|
||||
/* manager */
|
||||
|
||||
struct manager {
|
||||
sd_event *event;
|
||||
sd_bus *bus;
|
||||
sd_event_source *sigs[_NSIG];
|
||||
struct udev *udev;
|
||||
struct udev_monitor *udev_mon;
|
||||
sd_event_source *udev_mon_source;
|
||||
|
||||
unsigned int peer_ids;
|
||||
|
||||
size_t link_cnt;
|
||||
size_t peer_cnt;
|
||||
struct shl_htable links;
|
||||
struct shl_htable peers;
|
||||
|
||||
char *friendly_name;
|
||||
};
|
||||
|
||||
#define MANAGER_FIRST_LINK(_m) \
|
||||
SHL_HTABLE_FIRST_MACRO(&(_m)->links, link_from_htable)
|
||||
#define MANAGER_FOREACH_LINK(_i, _m) \
|
||||
SHL_HTABLE_FOREACH_MACRO(_i, &(_m)->links, link_from_htable)
|
||||
#define MANAGER_FOREACH_PEER(_i, _m) \
|
||||
SHL_HTABLE_FOREACH_MACRO(_i, &(_m)->peers, peer_from_htable)
|
||||
|
||||
int manager_dbus_connect(struct manager *m);
|
||||
void manager_dbus_disconnect(struct manager *m);
|
||||
|
||||
struct link *manager_find_link(struct manager *m, const char *name);
|
||||
struct peer *manager_find_peer(struct manager *m, const char *name);
|
||||
|
||||
/* dbus */
|
||||
|
||||
void peer_dbus_provision_request(struct peer *p,
|
||||
const char *type,
|
||||
const char *pin);
|
||||
_shl_sentinel_
|
||||
void peer_dbus_properties_changed(struct peer *p, const char *prop, ...);
|
||||
void peer_dbus_added(struct peer *p);
|
||||
void peer_dbus_removed(struct peer *p);
|
||||
|
||||
_shl_sentinel_
|
||||
void link_dbus_properties_changed(struct link *l, const char *prop, ...);
|
||||
void link_dbus_scan_stopped(struct link *l);
|
||||
void link_dbus_added(struct link *l);
|
||||
void link_dbus_removed(struct link *l);
|
||||
|
||||
/* cli arguments */
|
||||
|
||||
extern bool arg_manage_wifi;
|
||||
extern const char *arg_wpa_rundir;
|
||||
extern const char *arg_wpa_bindir;
|
||||
|
||||
#endif /* MIRACLED_H */
|
||||
|
|
Loading…
Reference in a new issue