forked from enlightenment/enlightenment
904 lines
26 KiB
C
904 lines
26 KiB
C
#include "e_mod_main.h"
|
|
|
|
#define CONNMAN_BUS_NAME "net.connman"
|
|
#define CONNMAN_MANAGER_IFACE CONNMAN_BUS_NAME ".Manager"
|
|
#define CONNMAN_SERVICE_IFACE CONNMAN_BUS_NAME ".Service"
|
|
#define CONNMAN_TECHNOLOGY_IFACE CONNMAN_BUS_NAME ".Technology"
|
|
|
|
#define MILLI_PER_SEC 1000
|
|
#define CONNMAN_CONNECTION_TIMEOUT 60 * MILLI_PER_SEC
|
|
|
|
static unsigned int init_count;
|
|
static Eldbus_Connection *conn;
|
|
static struct Connman_Manager *connman_manager;
|
|
static E_Connman_Agent *agent;
|
|
|
|
E_API int E_CONNMAN_EVENT_MANAGER_IN;
|
|
E_API 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 void _dbus_str_array_to_eina(Eldbus_Message_Iter *value, Eina_Array **old,
|
|
unsigned nelem)
|
|
{
|
|
Eldbus_Message_Iter *itr_array;
|
|
Eina_Array *array;
|
|
const char *s;
|
|
EINA_SAFETY_ON_NULL_RETURN(value);
|
|
EINA_SAFETY_ON_NULL_RETURN(old);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN(eldbus_message_iter_arguments_get(value, "as",
|
|
&itr_array));
|
|
|
|
array = *old;
|
|
if (array == NULL)
|
|
{
|
|
array = eina_array_new(nelem);
|
|
*old = array;
|
|
}
|
|
else
|
|
_eina_str_array_clean(array);
|
|
|
|
while (eldbus_message_iter_get_and_next(itr_array, 's', &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 _service_parse_prop_changed(struct Connman_Service *cs,
|
|
const char *prop_name,
|
|
Eldbus_Message_Iter *value)
|
|
{
|
|
DBG("service %p %s prop %s", cs, cs->path, prop_name);
|
|
|
|
if (strcmp(prop_name, "State") == 0)
|
|
{
|
|
const char *state;
|
|
EINA_SAFETY_ON_FALSE_RETURN(eldbus_message_iter_arguments_get(value,
|
|
"s",
|
|
&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;
|
|
EINA_SAFETY_ON_FALSE_RETURN(eldbus_message_iter_arguments_get(value,
|
|
"s",
|
|
&name));
|
|
free(cs->name);
|
|
cs->name = strdup(name);
|
|
DBG("New name: %s", cs->name);
|
|
}
|
|
else if (strcmp(prop_name, "Type") == 0)
|
|
{
|
|
const char *type;
|
|
EINA_SAFETY_ON_FALSE_RETURN(eldbus_message_iter_arguments_get(value,
|
|
"s",
|
|
&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;
|
|
EINA_SAFETY_ON_FALSE_RETURN(eldbus_message_iter_arguments_get(value,
|
|
"y",
|
|
&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,
|
|
Eldbus_Message_Iter *props)
|
|
{
|
|
Eldbus_Message_Iter *dict;
|
|
while (eldbus_message_iter_get_and_next(props, 'e', &dict))
|
|
{
|
|
char *name;
|
|
Eldbus_Message_Iter *var;
|
|
|
|
if (!eldbus_message_iter_arguments_get(dict, "sv", &name, &var))
|
|
continue;
|
|
_service_parse_prop_changed(cs, name, var);
|
|
}
|
|
}
|
|
|
|
static void _service_prop_changed(void *data, const Eldbus_Message *msg)
|
|
{
|
|
struct Connman_Service *cs = data;
|
|
Eldbus_Message_Iter *var;
|
|
const char *name;
|
|
|
|
if (!eldbus_message_arguments_get(msg, "sv", &name, &var))
|
|
return;
|
|
|
|
_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)
|
|
{
|
|
Eldbus_Object *obj;
|
|
if (!cs)
|
|
return;
|
|
|
|
if (cs->pending.connect)
|
|
{
|
|
eldbus_pending_cancel(cs->pending.connect);
|
|
free(cs->pending.data);
|
|
}
|
|
else if (cs->pending.disconnect)
|
|
{
|
|
eldbus_pending_cancel(cs->pending.disconnect);
|
|
free(cs->pending.data);
|
|
}
|
|
else if (cs->pending.remov)
|
|
{
|
|
eldbus_pending_cancel(cs->pending.remov);
|
|
free(cs->pending.data);
|
|
}
|
|
|
|
free(cs->name);
|
|
_eina_str_array_clean(cs->security);
|
|
eina_array_free(cs->security);
|
|
eina_stringshare_del(cs->path);
|
|
obj = eldbus_proxy_object_get(cs->service_iface);
|
|
eldbus_proxy_unref(cs->service_iface);
|
|
eldbus_object_unref(obj);
|
|
|
|
free(cs);
|
|
}
|
|
|
|
static struct Connman_Service *_service_new(const char *path, Eldbus_Message_Iter *props)
|
|
{
|
|
struct Connman_Service *cs;
|
|
Eldbus_Object *obj;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
|
|
|
|
cs = calloc(1, sizeof(*cs));
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cs, NULL);
|
|
|
|
cs->path = eina_stringshare_add(path);
|
|
|
|
obj = eldbus_object_get(conn, CONNMAN_BUS_NAME, path);
|
|
cs->service_iface = eldbus_proxy_get(obj, CONNMAN_SERVICE_IFACE);
|
|
eldbus_proxy_signal_handler_add(cs->service_iface, "PropertyChanged",
|
|
_service_prop_changed, cs);
|
|
|
|
_service_prop_dict_changed(cs, props);
|
|
return cs;
|
|
}
|
|
|
|
static void _service_connection_cb(void *data, const Eldbus_Message *msg,
|
|
Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
struct connection_data *cd = data;
|
|
|
|
if (cd->cb)
|
|
{
|
|
const char *s = NULL;
|
|
eldbus_message_error_get(msg, NULL, &s);
|
|
cd->cb(cd->user_data, s);
|
|
}
|
|
|
|
cd->cs->pending.connect = NULL;
|
|
cd->cs->pending.disconnect = NULL;
|
|
cd->cs->pending.remov = NULL;
|
|
cd->cs->pending.data = NULL;
|
|
|
|
free(cd);
|
|
}
|
|
|
|
bool econnman_service_connect(struct Connman_Service *cs,
|
|
Econnman_Simple_Cb cb, void *data)
|
|
{
|
|
struct connection_data *cd;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cs, false);
|
|
|
|
if (cs->pending.connect || cs->pending.disconnect || cs->pending.remov)
|
|
{
|
|
ERR("Pending connection: connect=%p disconnect=%p remov=%p", cs->pending.connect,
|
|
cs->pending.disconnect, cs->pending.remov);
|
|
return 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 = eldbus_proxy_call(cs->service_iface, "Connect",
|
|
_service_connection_cb, cd,
|
|
CONNMAN_CONNECTION_TIMEOUT, "");
|
|
return true;
|
|
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool econnman_service_disconnect(struct Connman_Service *cs,
|
|
Econnman_Simple_Cb cb, void *data)
|
|
{
|
|
struct connection_data *cd;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cs, false);
|
|
|
|
if (cs->pending.connect || cs->pending.disconnect || cs->pending.remov)
|
|
{
|
|
ERR("Pending connection: connect=%p disconnect=%p remov=%p", cs->pending.connect,
|
|
cs->pending.disconnect, cs->pending.remov);
|
|
return 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.disconnect = eldbus_proxy_call(cs->service_iface, "Disconnect",
|
|
_service_connection_cb, cd,
|
|
-1, "");
|
|
return true;
|
|
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool econnman_service_remove(struct Connman_Service *cs,
|
|
Econnman_Simple_Cb cb, void *data)
|
|
{
|
|
struct connection_data *cd;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cs, false);
|
|
|
|
if (cs->pending.connect || cs->pending.disconnect || cs->pending.remov)
|
|
{
|
|
ERR("Pending connection: connect=%p disconnect=%p remov=%p", cs->pending.connect,
|
|
cs->pending.disconnect, cs->pending.remov);
|
|
return 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.remov = eldbus_proxy_call(cs->service_iface, "Remove",
|
|
_service_connection_cb, cd,
|
|
-1, "");
|
|
return true;
|
|
|
|
fail:
|
|
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->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,
|
|
Eldbus_Message_Iter *array)
|
|
{
|
|
const char *path;
|
|
while (eldbus_message_iter_get_and_next(array, 'o', &path))
|
|
{
|
|
struct Connman_Service *cs;
|
|
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, const Eldbus_Message *msg)
|
|
{
|
|
struct Connman_Manager *cm = data;
|
|
Eldbus_Message_Iter *changed, *removed, *s;
|
|
Eina_Inlist *tmp = NULL;
|
|
|
|
if (cm->pending.get_services)
|
|
return;
|
|
|
|
if (!eldbus_message_arguments_get(msg, "a(oa{sv})ao", &changed, &removed))
|
|
{
|
|
ERR("Error getting arguments");
|
|
return;
|
|
}
|
|
|
|
_manager_services_remove(cm, removed);
|
|
|
|
while (eldbus_message_iter_get_and_next(changed, 'r', &s))
|
|
{
|
|
struct Connman_Service *cs;
|
|
const char *path;
|
|
Eldbus_Message_Iter *array;
|
|
|
|
if (!eldbus_message_iter_arguments_get(s, "oa{sv}", &path, &array))
|
|
continue;
|
|
|
|
cs = econnman_manager_find_service(cm, path);
|
|
if (!cs)
|
|
{
|
|
cs = _service_new(path, array);
|
|
DBG("Added service: %p %s", cs, path);
|
|
}
|
|
else
|
|
{
|
|
_service_prop_dict_changed(cs, array);
|
|
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, const Eldbus_Message *msg,
|
|
Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
struct Connman_Manager *cm = data;
|
|
Eldbus_Message_Iter *array, *s;
|
|
const char *name, *text;
|
|
|
|
cm->pending.get_services = NULL;
|
|
|
|
if (eldbus_message_error_get(msg, &name, &text))
|
|
{
|
|
ERR("Could not get services. %s: %s", name, text);
|
|
return;
|
|
}
|
|
DBG("cm->services=%p", cm->services);
|
|
|
|
if (!eldbus_message_arguments_get(msg, "a(oa{sv})", &array))
|
|
{
|
|
ERR("Error getting array");
|
|
return;
|
|
}
|
|
|
|
while (eldbus_message_iter_get_and_next(array, 'r', &s))
|
|
{
|
|
struct Connman_Service *cs;
|
|
const char *path;
|
|
Eldbus_Message_Iter *inner_array;
|
|
|
|
if (!eldbus_message_iter_arguments_get(s, "oa{sv}", &path, &inner_array))
|
|
continue;
|
|
|
|
cs = _service_new(path, inner_array);
|
|
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,
|
|
Eldbus_Message_Iter *value)
|
|
{
|
|
if (strcmp(name, "State") == 0)
|
|
{
|
|
const char *state;
|
|
if (!eldbus_message_iter_arguments_get(value, "s", &state))
|
|
return false;
|
|
DBG("New state: %s", state);
|
|
cm->state = str_to_state(state);
|
|
}
|
|
else if (strcmp(name, "OfflineMode") == 0)
|
|
{
|
|
if (!eldbus_message_iter_arguments_get(value, "b", &cm->offline_mode))
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
|
|
econnman_mod_manager_update(cm);
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
_manager_prop_changed(void *data, const Eldbus_Message *msg)
|
|
{
|
|
struct Connman_Manager *cm = data;
|
|
Eldbus_Message_Iter *var;
|
|
const char *name;
|
|
|
|
if (!eldbus_message_arguments_get(msg, "sv", &name, &var))
|
|
{
|
|
ERR("Could not parse message %p", msg);
|
|
return;
|
|
}
|
|
|
|
_manager_parse_prop_changed(cm, name, var);
|
|
}
|
|
|
|
static void _manager_get_prop_cb(void *data, const Eldbus_Message *msg,
|
|
Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
struct Connman_Manager *cm = data;
|
|
Eldbus_Message_Iter *array, *dict;
|
|
const char *name, *text;
|
|
|
|
if (eldbus_message_error_get(msg, &name, &text))
|
|
{
|
|
ERR("Could not get properties. %s: %s", name, text);
|
|
return;
|
|
}
|
|
|
|
if (!eldbus_message_arguments_get(msg, "a{sv}", &array))
|
|
{
|
|
ERR("Error getting arguments.");
|
|
return;
|
|
}
|
|
|
|
while (eldbus_message_iter_get_and_next(array, 'e', &dict))
|
|
{
|
|
const char *key;
|
|
Eldbus_Message_Iter *var;
|
|
|
|
if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &var))
|
|
continue;
|
|
_manager_parse_prop_changed(cm, key, var);
|
|
}
|
|
}
|
|
|
|
static bool _manager_parse_wifi_prop_changed(struct Connman_Manager *cm,
|
|
const char *name,
|
|
Eldbus_Message_Iter *value)
|
|
{
|
|
if (!strcmp(name, "Powered"))
|
|
return eldbus_message_iter_arguments_get(value, "b", &cm->powered);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
static void _manager_wifi_prop_changed(void *data, const Eldbus_Message *msg)
|
|
{
|
|
struct Connman_Manager *cm = data;
|
|
Eldbus_Message_Iter *var;
|
|
const char *name;
|
|
|
|
if (!eldbus_message_arguments_get(msg, "sv", &name, &var))
|
|
{
|
|
ERR("Could not parse message %p", msg);
|
|
return;
|
|
}
|
|
|
|
_manager_parse_wifi_prop_changed(cm, name, var);
|
|
}
|
|
|
|
static void _manager_get_wifi_prop_cb(void *data, const Eldbus_Message *msg,
|
|
Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
struct Connman_Manager *cm = data;
|
|
Eldbus_Message_Iter *array, *dict;
|
|
const char *name, *message;
|
|
|
|
cm->pending.get_wifi_properties = NULL;
|
|
|
|
if (eldbus_message_error_get(msg, &name, &message))
|
|
{
|
|
ERR("Could not get properties. %s: %s", name, message);
|
|
return;
|
|
}
|
|
|
|
if (!eldbus_message_arguments_get(msg, "a{sv}", &array))
|
|
{
|
|
ERR("Error getting arguments.");
|
|
return;
|
|
}
|
|
|
|
while (eldbus_message_iter_get_and_next(array, 'e', &dict))
|
|
{
|
|
Eldbus_Message_Iter *var;
|
|
const char *key;
|
|
|
|
if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &var))
|
|
continue;
|
|
_manager_parse_wifi_prop_changed(cm, key, var);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_manager_agent_unregister(struct Connman_Manager *cm)
|
|
{
|
|
eldbus_proxy_call(cm->manager_iface, "UnregisterAgent", NULL, NULL, -1, "o",
|
|
AGENT_PATH);
|
|
}
|
|
|
|
static void
|
|
_manager_agent_register_cb(void *data EINA_UNUSED, const Eldbus_Message *msg,
|
|
Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
const char *name, *text;
|
|
|
|
if (eldbus_message_error_get(msg, &name, &text))
|
|
{
|
|
WRN("Could not register agent. %s: %s", name, text);
|
|
return;
|
|
}
|
|
|
|
INF("Agent registered");
|
|
}
|
|
|
|
static void
|
|
_manager_agent_register(struct Connman_Manager *cm)
|
|
{
|
|
if (!cm)
|
|
return;
|
|
|
|
eldbus_proxy_call(cm->manager_iface, "RegisterAgent",
|
|
_manager_agent_register_cb, NULL, -1, "o", AGENT_PATH);
|
|
}
|
|
|
|
static void _manager_free(struct Connman_Manager *cm)
|
|
{
|
|
Eldbus_Object *obj;
|
|
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)
|
|
eldbus_pending_cancel(cm->pending.get_services);
|
|
|
|
if (cm->pending.get_wifi_properties)
|
|
eldbus_pending_cancel(cm->pending.get_wifi_properties);
|
|
|
|
if (cm->pending.set_powered)
|
|
eldbus_pending_cancel(cm->pending.set_powered);
|
|
|
|
eina_stringshare_del(cm->path);
|
|
obj = eldbus_proxy_object_get(cm->manager_iface);
|
|
eldbus_proxy_unref(cm->manager_iface);
|
|
eldbus_object_unref(obj);
|
|
obj = eldbus_proxy_object_get(cm->technology_iface);
|
|
eldbus_proxy_unref(cm->technology_iface);
|
|
eldbus_object_unref(obj);
|
|
free(cm);
|
|
}
|
|
|
|
static void _manager_powered_cb(void *data, const Eldbus_Message *msg,
|
|
Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
Eldbus_Pending *p;
|
|
struct Connman_Manager *cm = data;
|
|
const char *error_name, *error_msg;
|
|
|
|
cm->pending.set_powered = NULL;
|
|
|
|
if (eldbus_message_error_get(msg, &error_name, &error_msg))
|
|
{
|
|
ERR("Error: %s %s", error_name, error_msg);
|
|
return;
|
|
}
|
|
if (cm->pending.get_wifi_properties)
|
|
eldbus_pending_cancel(cm->pending.get_wifi_properties);
|
|
p = eldbus_proxy_call(cm->technology_iface, "GetProperties",
|
|
_manager_get_wifi_prop_cb, cm, -1, "");
|
|
cm->pending.get_wifi_properties = p;
|
|
}
|
|
|
|
void econnman_powered_set(struct Connman_Manager *cm, Eina_Bool powered)
|
|
{
|
|
Eldbus_Message_Iter *main_iter, *var;
|
|
Eldbus_Message *msg;
|
|
|
|
if (cm->pending.set_powered)
|
|
eldbus_pending_cancel(cm->pending.set_powered);
|
|
|
|
msg = eldbus_proxy_method_call_new(cm->technology_iface, "SetProperty");
|
|
main_iter = eldbus_message_iter_get(msg);
|
|
eldbus_message_iter_basic_append(main_iter, 's', "Powered");
|
|
var = eldbus_message_iter_container_new(main_iter, 'v', "b");
|
|
eldbus_message_iter_basic_append(var, 'b', powered);
|
|
eldbus_message_iter_container_close(main_iter, var);
|
|
|
|
cm->pending.set_powered = eldbus_proxy_send(cm->technology_iface, msg,
|
|
_manager_powered_cb, cm, -1);
|
|
}
|
|
|
|
static struct Connman_Manager *_manager_new(void)
|
|
{
|
|
const char *path = "/";
|
|
struct Connman_Manager *cm;
|
|
Eldbus_Object *obj;
|
|
|
|
cm = calloc(1, sizeof(*cm));
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(cm, NULL);
|
|
|
|
|
|
obj = eldbus_object_get(conn, CONNMAN_BUS_NAME, "/");
|
|
cm->manager_iface = eldbus_proxy_get(obj, CONNMAN_MANAGER_IFACE);
|
|
obj = eldbus_object_get(conn, CONNMAN_BUS_NAME,
|
|
"/net/connman/technology/wifi");
|
|
cm->technology_iface = eldbus_proxy_get(obj, CONNMAN_TECHNOLOGY_IFACE);
|
|
|
|
cm->path = eina_stringshare_add(path);
|
|
|
|
eldbus_proxy_signal_handler_add(cm->manager_iface, "PropertyChanged",
|
|
_manager_prop_changed, cm);
|
|
eldbus_proxy_signal_handler_add(cm->manager_iface, "ServicesChanged",
|
|
_manager_services_changed, cm);
|
|
eldbus_proxy_signal_handler_add(cm->technology_iface, "PropertyChanged",
|
|
_manager_wifi_prop_changed, cm);
|
|
|
|
/*
|
|
* 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 = eldbus_proxy_call(cm->manager_iface,
|
|
"GetServices",
|
|
_manager_get_services_cb, cm,
|
|
-1, "");
|
|
eldbus_proxy_call(cm->manager_iface, "GetProperties", _manager_get_prop_cb, cm,
|
|
-1, "");
|
|
cm->pending.get_wifi_properties = eldbus_proxy_call(cm->technology_iface,
|
|
"GetProperties",
|
|
_manager_get_wifi_prop_cb,
|
|
cm, -1, "");
|
|
|
|
return cm;
|
|
}
|
|
|
|
static inline void _e_connman_system_name_owner_exit(void)
|
|
{
|
|
if (!connman_manager)
|
|
return;
|
|
_manager_agent_unregister(connman_manager);
|
|
econnman_mod_manager_inout(NULL);
|
|
_manager_free(connman_manager);
|
|
connman_manager = NULL;
|
|
|
|
ecore_event_add(E_CONNMAN_EVENT_MANAGER_OUT, NULL, NULL, NULL);
|
|
}
|
|
|
|
static inline void _e_connman_system_name_owner_enter(const char *owner EINA_UNUSED)
|
|
{
|
|
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 EINA_UNUSED,
|
|
const char *bus EINA_UNUSED,
|
|
const char *from EINA_UNUSED,
|
|
const char *to)
|
|
{
|
|
if (to[0])
|
|
_e_connman_system_name_owner_enter(to);
|
|
else
|
|
_e_connman_system_name_owner_exit();
|
|
}
|
|
|
|
/**
|
|
* 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(Eldbus_Connection *eldbus_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 = eldbus_conn;
|
|
eldbus_name_owner_changed_callback_add(conn, CONNMAN_BUS_NAME,
|
|
_e_connman_system_name_owner_changed,
|
|
NULL, EINA_TRUE);
|
|
agent = econnman_agent_new(eldbus_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;
|
|
|
|
eldbus_name_owner_changed_callback_del(conn, CONNMAN_BUS_NAME,
|
|
_e_connman_system_name_owner_changed,
|
|
NULL);
|
|
_e_connman_system_name_owner_exit();
|
|
if (agent)
|
|
econnman_agent_del(agent);
|
|
if (conn)
|
|
eldbus_connection_unref(conn);
|
|
agent = NULL;
|
|
conn = NULL;
|
|
|
|
E_CONNMAN_EVENT_MANAGER_OUT = 0;
|
|
E_CONNMAN_EVENT_MANAGER_IN = 0;
|
|
|
|
return init_count;
|
|
}
|