enlightenment/src/modules/connman/e_connman.c

971 lines
26 KiB
C

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "E_Connman.h"
#include "agent.h"
#define CONNMAN_BUS_NAME "net.connman"
#define CONNMAN_MANAGER_IFACE CONNMAN_BUS_NAME ".Manager"
#define CONNMAN_SERVICE_IFACE CONNMAN_BUS_NAME ".Service"
#define MILLI_PER_SEC 1000
#define CONNMAN_CONNECTION_TIMEOUT 60 * MILLI_PER_SEC
static unsigned int init_count;
static E_DBus_Connection *conn;
static char *bus_owner;
static struct Connman_Manager *connman_manager;
static E_Connman_Agent *agent;
static DBusPendingCall *pending_get_name_owner;
static E_DBus_Signal_Handler *handler_name_owner;
EAPI int E_CONNMAN_EVENT_MANAGER_IN;
EAPI int E_CONNMAN_EVENT_MANAGER_OUT;
/* utility functions */
static void _eina_str_array_clean(Eina_Array *array)
{
const char *item;
Eina_Array_Iterator itr;
unsigned int i;
EINA_ARRAY_ITER_NEXT(array, i, item, itr)
eina_stringshare_del(item);
eina_array_clean(array);
}
static bool _dbus_bool_get(DBusMessageIter *itr)
{
dbus_bool_t val;
dbus_message_iter_get_basic(itr, &val);
return val;
}
static void _dbus_str_array_to_eina(DBusMessageIter *value, Eina_Array **old,
unsigned nelem)
{
DBusMessageIter itr;
Eina_Array *array;
EINA_SAFETY_ON_NULL_RETURN(value);
EINA_SAFETY_ON_NULL_RETURN(old);
EINA_SAFETY_ON_FALSE_RETURN(
dbus_message_iter_get_arg_type(value) == DBUS_TYPE_ARRAY);
dbus_message_iter_recurse(value, &itr);
array = *old;
if (array == NULL)
{
array = eina_array_new(nelem);
*old = array;
}
else
_eina_str_array_clean(array);
for (; dbus_message_iter_get_arg_type(&itr) != DBUS_TYPE_INVALID;
dbus_message_iter_next(&itr))
{
const char *s;
if (dbus_message_iter_get_arg_type(&itr) != DBUS_TYPE_STRING)
{
ERR("Unexpected D-Bus type %d",
dbus_message_iter_get_arg_type(&itr));
continue;
}
dbus_message_iter_get_basic(&itr, &s);
eina_array_push(array, eina_stringshare_add(s));
DBG("Push %s", s);
}
return;
}
static enum Connman_State str_to_state(const char *s)
{
if (!strcmp(s, "offline"))
return CONNMAN_STATE_OFFLINE;
if (!strcmp(s, "idle"))
return CONNMAN_STATE_IDLE;
if (!strcmp(s, "association"))
return CONNMAN_STATE_ASSOCIATION;
if (!strcmp(s, "configuration"))
return CONNMAN_STATE_CONFIGURATION;
if (!strcmp(s, "ready"))
return CONNMAN_STATE_READY;
if (!strcmp(s, "online"))
return CONNMAN_STATE_ONLINE;
if (!strcmp(s, "disconnect"))
return CONNMAN_STATE_DISCONNECT;
if (!strcmp(s, "failure"))
return CONNMAN_STATE_FAILURE;
ERR("Unknown state %s", s);
return CONNMAN_STATE_NONE;
}
const char *econnman_state_to_str(enum Connman_State state)
{
switch (state)
{
case CONNMAN_STATE_OFFLINE:
return "offline";
case CONNMAN_STATE_IDLE:
return "idle";
case CONNMAN_STATE_ASSOCIATION:
return "association";
case CONNMAN_STATE_CONFIGURATION:
return "configuration";
case CONNMAN_STATE_READY:
return "ready";
case CONNMAN_STATE_ONLINE:
return "online";
case CONNMAN_STATE_DISCONNECT:
return "disconnect";
case CONNMAN_STATE_FAILURE:
return "failure";
case CONNMAN_STATE_NONE:
break;
}
return NULL;
}
static enum Connman_Service_Type str_to_type(const char *s)
{
if (!strcmp(s, "ethernet"))
return CONNMAN_SERVICE_TYPE_ETHERNET;
else if (!strcmp(s, "wifi"))
return CONNMAN_SERVICE_TYPE_WIFI;
else if (!strcmp(s, "bluetooth"))
return CONNMAN_SERVICE_TYPE_BLUETOOTH;
else if (!strcmp(s, "cellular"))
return CONNMAN_SERVICE_TYPE_CELLULAR;
DBG("Unknown type %s", s);
return CONNMAN_SERVICE_TYPE_NONE;
}
const char *econnman_service_type_to_str(enum Connman_Service_Type type)
{
switch (type)
{
case CONNMAN_SERVICE_TYPE_ETHERNET:
return "ethernet";
case CONNMAN_SERVICE_TYPE_WIFI:
return "wifi";
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
return "bluetooth";
case CONNMAN_SERVICE_TYPE_CELLULAR:
return "cellular";
case CONNMAN_SERVICE_TYPE_NONE:
break;
}
return "other";
}
/* ---- */
static void _connman_object_init(struct Connman_Object *obj, const char *path)
{
obj->path = eina_stringshare_add(path);
}
static void _connman_object_clear(struct Connman_Object *obj)
{
E_DBus_Signal_Handler *h;
EINA_LIST_FREE(obj->handlers, h)
e_dbus_signal_handler_del(conn, h);
eina_stringshare_del(obj->path);
}
static void _service_parse_prop_changed(struct Connman_Service *cs,
const char *prop_name,
DBusMessageIter *value)
{
DBG("service %p %s prop %s", cs, cs->obj.path, prop_name);
if (strcmp(prop_name, "State") == 0)
{
const char *state;
dbus_message_iter_get_basic(value, &state);
cs->state = str_to_state(state);
DBG("New state: %s %d", state, cs->state);
}
else if (strcmp(prop_name, "Name") == 0)
{
const char *name;
dbus_message_iter_get_basic(value, &name);
free(cs->name);
cs->name = strdup(name);
DBG("New name: %s", cs->name);
}
else if (strcmp(prop_name, "Type") == 0)
{
const char *type;
dbus_message_iter_get_basic(value, &type);
cs->type = str_to_type(type);
DBG("New type: %s %d", type, cs->type);
}
else if (strcmp(prop_name, "Strength") == 0)
{
uint8_t strength;
dbus_message_iter_get_basic(value, &strength);
cs->strength = strength;
DBG("New strength: %d", strength);;
}
else if (strcmp(prop_name, "Security") == 0)
{
DBG("Old security count: %d",
cs->security ? eina_array_count(cs->security) : 0);
_dbus_str_array_to_eina(value, &cs->security, 2);
DBG("New security count: %d", eina_array_count(cs->security));
}
}
static void _service_prop_dict_changed(struct Connman_Service *cs,
DBusMessageIter *dict)
{
for (; dbus_message_iter_get_arg_type(dict) != DBUS_TYPE_INVALID;
dbus_message_iter_next(dict))
{
DBusMessageIter entry, var;
const char *name;
dbus_message_iter_recurse(dict, &entry);
EINA_SAFETY_ON_FALSE_RETURN(
dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING);
dbus_message_iter_get_basic(&entry, &name);
dbus_message_iter_next(&entry);
EINA_SAFETY_ON_FALSE_RETURN(
dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_VARIANT);
dbus_message_iter_recurse(&entry, &var);
_service_parse_prop_changed(cs, name, &var);
}
}
static void _service_prop_changed(void *data, DBusMessage *msg)
{
struct Connman_Service *cs = data;
DBusMessageIter iter, var;
const char *name;
if (!msg || !dbus_message_iter_init(msg, &iter))
{
ERR("Could not parse message %p", msg);
return;
}
dbus_message_iter_get_basic(&iter, &name);
dbus_message_iter_next(&iter);
dbus_message_iter_recurse(&iter, &var);
_service_parse_prop_changed(cs, name, &var);
}
struct connection_data {
struct Connman_Service *cs;
Econnman_Simple_Cb cb;
void *user_data;
};
static void _service_free(struct Connman_Service *cs)
{
if (!cs)
return;
if (cs->pending.connect)
{
dbus_pending_call_cancel(cs->pending.connect);
free(cs->pending.data);
}
if (cs->pending.disconnect)
{
dbus_pending_call_cancel(cs->pending.disconnect);
free(cs->pending.data);
}
free(cs->name);
_eina_str_array_clean(cs->security);
eina_array_free(cs->security);
_connman_object_clear(&cs->obj);
free(cs);
}
static struct Connman_Service *_service_new(const char *path, DBusMessageIter *props)
{
struct Connman_Service *cs;
E_DBus_Signal_Handler *h;
EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
cs = calloc(1, sizeof(*cs));
EINA_SAFETY_ON_NULL_RETURN_VAL(cs, NULL);
_connman_object_init(&cs->obj, path);
h = e_dbus_signal_handler_add(conn, bus_owner,
path, CONNMAN_SERVICE_IFACE, "PropertyChanged",
_service_prop_changed, cs);
cs->obj.handlers = eina_list_append(cs->obj.handlers, h);
_service_prop_dict_changed(cs, props);
return cs;
}
static void _service_connection_cb(void *data, DBusMessage *reply,
DBusError *err)
{
struct connection_data *cd = data;
if (cd->cb)
{
const char *s = dbus_error_is_set(err) ? err->message : NULL;
cd->cb(cd->user_data, s);
}
cd->cs->pending.connect = NULL;
cd->cs->pending.disconnect = NULL;
cd->cs->pending.data = NULL;
free(cd);
}
bool econnman_service_connect(struct Connman_Service *cs,
Econnman_Simple_Cb cb, void *data)
{
DBusMessage *msg;
struct connection_data *cd;
EINA_SAFETY_ON_NULL_RETURN_VAL(cs, false);
if (cs->pending.connect || cs->pending.disconnect)
{
ERR("Pending connection: connect=%p disconnect=%p", cs->pending.connect,
cs->pending.disconnect);
return false;
}
msg = dbus_message_new_method_call(CONNMAN_BUS_NAME, cs->obj.path,
CONNMAN_SERVICE_IFACE, "Connect");
EINA_SAFETY_ON_NULL_RETURN_VAL(msg, false);
cd = calloc(1, sizeof(*cd));
EINA_SAFETY_ON_NULL_GOTO(cd, fail);
cd->cs = cs;
cd->cb = cb;
cd->user_data = data;
cs->pending.connect = e_dbus_message_send(conn, msg,
_service_connection_cb, CONNMAN_CONNECTION_TIMEOUT, cd);
return true;
fail:
dbus_message_unref(msg);
return false;
}
bool econnman_service_disconnect(struct Connman_Service *cs,
Econnman_Simple_Cb cb, void *data)
{
DBusMessage *msg;
struct connection_data *cd;
EINA_SAFETY_ON_NULL_RETURN_VAL(cs, false);
if (cs->pending.connect || cs->pending.disconnect)
{
ERR("Pending connection: connect=%p disconnect=%p", cs->pending.connect,
cs->pending.disconnect);
return false;
}
msg = dbus_message_new_method_call(CONNMAN_BUS_NAME, cs->obj.path,
CONNMAN_SERVICE_IFACE, "Disconnect");
EINA_SAFETY_ON_NULL_RETURN_VAL(msg, false);
cd = calloc(1, sizeof(*cd));
EINA_SAFETY_ON_NULL_GOTO(cd, fail);
cd->cs = cs;
cd->cb = cb;
cd->user_data = data;
cs->pending.connect = e_dbus_message_send(conn, msg,
_service_connection_cb, -1, cd);
return true;
fail:
dbus_message_unref(msg);
return false;
}
static struct Connman_Service *_manager_find_service_stringshared(
struct Connman_Manager *cm, const char *path)
{
struct Connman_Service *cs, *found = NULL;
EINA_INLIST_FOREACH(cm->services, cs)
{
if (cs->obj.path == path)
{
found = cs;
break;
}
}
return found;
}
struct Connman_Service *econnman_manager_find_service(struct Connman_Manager *cm,
const char *path)
{
struct Connman_Service *cs;
path = eina_stringshare_add(path);
cs = _manager_find_service_stringshared(cm, path);
eina_stringshare_del(path);
return cs;
}
static void _manager_services_remove(struct Connman_Manager *cm,
DBusMessageIter *array)
{
for (; dbus_message_iter_get_arg_type(array) != DBUS_TYPE_INVALID;
dbus_message_iter_next(array))
{
struct Connman_Service *cs;
const char *path;
if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_OBJECT_PATH)
{
ERR("Unexpected D-Bus type %d",
dbus_message_iter_get_arg_type(array));
continue;
}
dbus_message_iter_get_basic(array, &path);
cs = econnman_manager_find_service(cm, path);
if (cs == NULL)
{
ERR("Received object path '%s' to remove, but it's not in list",
path);
continue;
}
cm->services = eina_inlist_remove(cm->services, EINA_INLIST_GET(cs));
DBG("Removed service: %p %s", cs, path);
_service_free(cs);
}
}
static void _manager_services_changed(void *data, DBusMessage *msg)
{
struct Connman_Manager *cm = data;
DBusMessageIter iter, changed, removed;
Eina_Inlist *tmp = NULL;
if (cm->pending.get_services)
return;
dbus_message_iter_init(msg, &iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
{
ERR("type=%d", dbus_message_iter_get_arg_type(&iter));
return;
}
dbus_message_iter_recurse(&iter, &changed);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
{
ERR("type=%d", dbus_message_iter_get_arg_type(&iter));
return;
}
dbus_message_iter_recurse(&iter, &removed);
_manager_services_remove(cm, &removed);
for (; dbus_message_iter_get_arg_type(&changed) != DBUS_TYPE_INVALID;
dbus_message_iter_next(&changed))
{
struct Connman_Service *cs;
DBusMessageIter entry, dict;
const char *path;
dbus_message_iter_recurse(&changed, &entry);
if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_OBJECT_PATH)
{
ERR("Unexpected D-Bus type %d",
dbus_message_iter_get_arg_type(&entry));
continue;
}
dbus_message_iter_get_basic(&entry, &path);
cs = econnman_manager_find_service(cm, path);
dbus_message_iter_next(&entry);
if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_ARRAY)
{
ERR("Unexpected D-Bus type %d",
dbus_message_iter_get_arg_type(&entry));
continue;
}
dbus_message_iter_recurse(&entry, &dict);
if (cs == NULL)
{
cs = _service_new(path, &dict);
DBG("Added service: %p %s", cs, path);
}
else
{
_service_prop_dict_changed(cs, &dict);
cm->services = eina_inlist_remove(cm->services,
EINA_INLIST_GET(cs));
DBG("Changed service: %p %s", cs, path);
}
tmp = eina_inlist_append(tmp, EINA_INLIST_GET(cs));
}
cm->services = tmp;
econnman_mod_services_changed(cm);
}
static void _manager_get_services_cb(void *data, DBusMessage *reply,
DBusError *err)
{
struct Connman_Manager *cm = data;
DBusMessageIter iter, array;
cm->pending.get_services = NULL;
if (dbus_error_is_set(err))
{
DBG("Could not get services. %s: %s", err->name, err->message);
return;
}
DBG("cm->services=%p", cm->services);
dbus_message_iter_init(reply, &iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
{
ERR("type=%d", dbus_message_iter_get_arg_type(&iter));
return;
}
dbus_message_iter_recurse(&iter, &array);
for (; dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID;
dbus_message_iter_next(&array))
{
struct Connman_Service *cs;
const char *path;
DBusMessageIter entry, dict;
dbus_message_iter_recurse(&array, &entry);
dbus_message_iter_get_basic(&entry, &path);
dbus_message_iter_next(&entry);
dbus_message_iter_recurse(&entry, &dict);
cs = _service_new(path, &dict);
if (cs == NULL)
continue;
cm->services = eina_inlist_append(cm->services, EINA_INLIST_GET(cs));
DBG("Added service: %p %s", cs, path);
}
econnman_mod_services_changed(cm);
}
static bool _manager_parse_prop_changed(struct Connman_Manager *cm,
const char *name,
DBusMessageIter *value)
{
if (strcmp(name, "State") == 0)
{
const char *state;
dbus_message_iter_get_basic(value, &state);
DBG("New state: %s", state);
cm->state = str_to_state(state);
}
else if (strcmp(name, "OfflineMode") == 0)
cm->offline_mode = _dbus_bool_get(value);
else
return false;
econnman_mod_manager_update(cm);
return true;
}
static void _manager_prop_changed(void *data, DBusMessage *msg)
{
struct Connman_Manager *cm = data;
DBusMessageIter iter, var;
const char *name;
if (!msg || !dbus_message_iter_init(msg, &iter))
{
ERR("Could not parse message %p", msg);
return;
}
dbus_message_iter_get_basic(&iter, &name);
dbus_message_iter_next(&iter);
dbus_message_iter_recurse(&iter, &var);
_manager_parse_prop_changed(cm, name, &var);
}
static void _manager_get_prop_cb(void *data, DBusMessage *reply,
DBusError *err)
{
struct Connman_Manager *cm = data;
DBusMessageIter iter, dict;
cm->pending.get_properties = NULL;
if (dbus_error_is_set(err))
{
DBG("Could not get properties. %s: %s", err->name, err->message);
return;
}
dbus_message_iter_init(reply, &iter);
dbus_message_iter_recurse(&iter, &dict);
for (; dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID;
dbus_message_iter_next(&dict))
{
DBusMessageIter entry, var;
const char *name;
dbus_message_iter_recurse(&dict, &entry);
dbus_message_iter_get_basic(&entry, &name);
dbus_message_iter_next(&entry);
dbus_message_iter_recurse(&entry, &var);
_manager_parse_prop_changed(cm, name, &var);
}
}
static void
_manager_agent_unregister(void)
{
const char *path = AGENT_PATH;
DBusMessageIter itr;
DBusMessage *msg;
msg = dbus_message_new_method_call(CONNMAN_BUS_NAME, "/",
CONNMAN_MANAGER_IFACE, "UnregisterAgent");
if (!msg)
{
ERR("Could not create D-Bus message");
return;
}
dbus_message_iter_init_append(msg, &itr);
dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &path);
e_dbus_message_send(conn, msg, NULL, -1, NULL);
}
static void
_manager_agent_register_cb(void *data, DBusMessage *reply, DBusError *err)
{
struct Connman_Manager *cm = data;
cm->pending.register_agent = NULL;
if (dbus_error_is_set(err))
{
WRN("Could not register agent. %s: %s", err->name, err->message);
return;
}
INF("Agent registered");
}
static void
_manager_agent_register(struct Connman_Manager *cm)
{
const char *path = AGENT_PATH;
DBusMessageIter itr;
DBusMessage *msg;
if (!cm)
return;
msg = dbus_message_new_method_call(CONNMAN_BUS_NAME, "/",
CONNMAN_MANAGER_IFACE, "RegisterAgent");
if (!msg)
{
ERR("Could not create D-Bus message");
return;
}
dbus_message_iter_init_append(msg, &itr);
dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &path);
cm->pending.register_agent = e_dbus_message_send(conn, msg,
_manager_agent_register_cb,
-1, cm);
}
static void _manager_free(struct Connman_Manager *cm)
{
if (!cm)
return;
while (cm->services)
{
struct Connman_Service *cs = EINA_INLIST_CONTAINER_GET(cm->services,
struct Connman_Service);
cm->services = eina_inlist_remove(cm->services, cm->services);
_service_free(cs);
}
if (cm->pending.get_services)
{
dbus_pending_call_cancel(cm->pending.get_services);
cm->pending.get_services = NULL;
}
if (cm->pending.get_properties)
{
dbus_pending_call_cancel(cm->pending.get_properties);
cm->pending.get_properties = NULL;
}
if (cm->pending.register_agent)
{
dbus_pending_call_cancel(cm->pending.register_agent);
cm->pending.register_agent = NULL;
}
_connman_object_clear(&cm->obj);
free(cm);
}
static struct Connman_Manager *_manager_new(void)
{
DBusMessage *msg_props, *msg_services;
const char *path = "/";
struct E_DBus_Signal_Handler *h;
struct Connman_Manager *cm;
msg_services = dbus_message_new_method_call(CONNMAN_BUS_NAME, "/",
CONNMAN_MANAGER_IFACE, "GetServices");
msg_props = dbus_message_new_method_call(CONNMAN_BUS_NAME, "/",
CONNMAN_MANAGER_IFACE, "GetProperties");
if (!msg_services || !msg_services)
{
ERR("Could not create D-Bus messages");
return NULL;
}
cm = calloc(1, sizeof(*cm));
EINA_SAFETY_ON_NULL_RETURN_VAL(cm, NULL);
_connman_object_init(&cm->obj, path);
h = e_dbus_signal_handler_add(conn, bus_owner,
path, CONNMAN_MANAGER_IFACE, "PropertyChanged",
_manager_prop_changed, cm);
cm->obj.handlers = eina_list_append(cm->obj.handlers, h);
h = e_dbus_signal_handler_add(conn, bus_owner,
path, CONNMAN_MANAGER_IFACE, "ServicesChanged",
_manager_services_changed, cm);
cm->obj.handlers = eina_list_append(cm->obj.handlers, h);
/*
* PropertyChanged signal in service's path is guaranteed to arrive only
* after ServicesChanged above. So we only add the handler later, in a per
* service manner.
*/
cm->pending.get_services = e_dbus_message_send(conn, msg_services,
_manager_get_services_cb, -1, cm);
cm->pending.get_properties = e_dbus_message_send(conn, msg_props,
_manager_get_prop_cb, -1, cm);
return cm;
}
static inline void _e_connman_system_name_owner_exit(void)
{
_manager_agent_unregister();
econnman_mod_manager_inout(NULL);
_manager_free(connman_manager);
connman_manager = NULL;
free(bus_owner);
bus_owner = NULL;
ecore_event_add(E_CONNMAN_EVENT_MANAGER_OUT, NULL, NULL, NULL);
}
static inline void _e_connman_system_name_owner_enter(const char *owner)
{
bus_owner = strdup(owner);
connman_manager = _manager_new();
_manager_agent_register(connman_manager);
ecore_event_add(E_CONNMAN_EVENT_MANAGER_IN, NULL, NULL, NULL);
econnman_mod_manager_inout(connman_manager);
}
static void _e_connman_system_name_owner_changed(void *data, DBusMessage *msg)
{
const char *name, *from, *to;
DBusError err;
dbus_error_init(&err);
if (!dbus_message_get_args(msg, &err,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &from,
DBUS_TYPE_STRING, &to,
DBUS_TYPE_INVALID))
{
ERR("could not get NameOwnerChanged arguments: %s: %s",
err.name, err.message);
dbus_error_free(&err);
return;
}
if (strcmp(name, CONNMAN_BUS_NAME) != 0)
return;
DBG("NameOwnerChanged %s from=[%s] to=[%s]", name, from, to);
if (from[0] == '\0' && to[0] != '\0')
_e_connman_system_name_owner_enter(to);
else if (from[0] != '\0' && to[0] == '\0')
_e_connman_system_name_owner_exit();
else
ERR("unknow change from %s to %s", from, to);
}
static void
_e_connman_get_name_owner(void *data, DBusMessage *msg, DBusError *err)
{
const char *owner;
pending_get_name_owner = NULL;
/* Do nothing if already received a signal */
if (bus_owner)
return;
DBG("get_name_owner msg=%p", msg);
if (dbus_error_is_set(err))
{
if (strcmp(err->name, DBUS_ERROR_NAME_HAS_NO_OWNER) != 0)
ERR("could not get bus name owner: %s %s", err->name, err->message);
return;
}
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &owner,
DBUS_TYPE_INVALID))
{
ERR("Could not get name owner");
return;
}
_e_connman_system_name_owner_enter(owner);
}
/**
* Initialize E Connection Manager (E_Connman) system.
*
* This will connect to ConnMan through DBus and watch for it going in and out.
*
* Interesting events are:
* - E_CONNMAN_EVENT_MANAGER_IN: issued when connman is avaiable.
* - E_CONNMAN_EVENT_MANAGER_OUT: issued when connman connection is lost.
*/
unsigned int
e_connman_system_init(E_DBus_Connection *edbus_conn)
{
init_count++;
if (init_count > 1)
return init_count;
E_CONNMAN_EVENT_MANAGER_IN = ecore_event_type_new();
E_CONNMAN_EVENT_MANAGER_OUT = ecore_event_type_new();
conn = edbus_conn;
handler_name_owner = e_dbus_signal_handler_add(conn,
E_DBUS_FDO_BUS, E_DBUS_FDO_PATH, E_DBUS_FDO_INTERFACE,
"NameOwnerChanged", _e_connman_system_name_owner_changed,
NULL);
pending_get_name_owner = e_dbus_get_name_owner(conn,
CONNMAN_BUS_NAME, _e_connman_get_name_owner,
NULL);
agent = econnman_agent_new(edbus_conn);
return init_count;
}
/**
* Shutdown ConnMan system
*
* When count drops to 0 resources will be released and no calls should be
* made anymore.
*/
unsigned int
e_connman_system_shutdown(void)
{
if (init_count == 0)
{
ERR("connman system already shut down.");
return 0;
}
init_count--;
if (init_count > 0)
return init_count;
e_dbus_signal_handler_del(conn, handler_name_owner);
if (pending_get_name_owner)
dbus_pending_call_cancel(pending_get_name_owner);
if (agent)
econnman_agent_del(agent);
agent = NULL;
conn = NULL;
E_CONNMAN_EVENT_MANAGER_OUT = 0;
E_CONNMAN_EVENT_MANAGER_IN = 0;
return init_count;
}