efl/src/lib/ecore_con/efl_net_session-connman.c

831 lines
25 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "Ecore.h"
#include "Ecore_Con.h"
#include "ecore_con_private.h"
#include "efl_net-connman.h"
typedef struct
{
Eldbus_Proxy *proxy; /* net.connman.Session */
Eldbus_Service_Interface *notifier; /* net.connman.Notification */
Eldbus_Pending *mgr_pending; /* on efl_net_connman_manager_get(), local proxy doesn't need it, done automatically */
struct {
Eldbus_Pending *pending;
Eina_Bool connected; /* if should be connected or not */
Eina_Bool online_required;
Efl_Net_Session_Technology technologies_allowed;
} connect;
/* properties notified by session, local cache */
Eina_Stringshare *name;
Eina_Stringshare *interface;
struct {
Eina_Stringshare *address;
Eina_Stringshare *netmask;
Eina_Stringshare *gateway;
} ipv4;
struct {
Eina_Stringshare *address;
Eina_Stringshare *netmask;
Eina_Stringshare *gateway;
uint8_t prefix_length;
} ipv6;
Efl_Net_Session_State state;
Efl_Net_Session_Technology technology;
} Efl_Net_Session_Data;
#define MY_CLASS EFL_NET_SESSION_CLASS
/* will SET BIT for technology, start with '0' for multiple techs */
static Eina_Bool
_efl_net_session_technology_from_str(const char *str, Efl_Net_Session_Technology *tech)
{
if (0) { }
#define MAP(X, s) \
else if (strcmp(str, s) == 0) *tech |= EFL_NET_SESSION_TECHNOLOGY_ ## X
MAP(ALL, "*");
MAP(ETHERNET, "ethernet");
MAP(WIFI, "wifi");
MAP(BLUETOOTH, "bluetooth");
MAP(CELLULAR, "cellular");
MAP(VPN, "vpn");
MAP(GADGET, "gadget");
#undef MAP
else if (str[0]) /* empty bearer = no technology */
{
WRN("Unknown technology name: %s", str);
return EINA_FALSE;
}
return EINA_TRUE;
}
static void _efl_net_session_connect_do(Eo *o, Efl_Net_Session_Data *pd);
/* NOTE: unlike most DBus servers where you create paths using
* ObjectManager and monitor properties on them using PropertyManager,
* ConnMan doesn't use any of those and their API for Session is
* different from all others in ConnMan itself:
*
* 1 - create a local service 'notifier' implementing
* net.connman.Notification, with method Release() and
* Update(dict settings).
*
* 2 - call / CreateSession(dict settings, path notifier), get an
* object path representing your session
*
* 3 - call Change(setting, value), Connect(), Disconnect() on
* object path returned on #2
*
* 4 - get Update() to be called on your local service notifier specified
* on step #1.
*/
static Eldbus_Message *
_efl_net_session_notifier_release(const Eldbus_Service_Interface *service, const Eldbus_Message *msg)
{
Eo *o = eldbus_service_object_data_get(service, "efl_net");
DBG("Session %p is released %s", o, eldbus_message_path_get(msg));
return eldbus_message_method_return_new(msg);
}
static Eina_Error
_efl_net_session_notifier_update_state(Efl_Net_Session_Data *pd, Eldbus_Message_Iter *var)
{
const char *str;
if (!eldbus_message_iter_arguments_get(var, "s", &str))
return EINVAL;
if (strcmp(str, "disconnected") == 0)
pd->state = EFL_NET_SESSION_STATE_OFFLINE;
else if (strcmp(str, "connected") == 0)
pd->state = EFL_NET_SESSION_STATE_LOCAL;
else if (strcmp(str, "online") == 0)
pd->state = EFL_NET_SESSION_STATE_ONLINE;
else
return EINVAL;
return 0;
}
static Eina_Error
_efl_net_session_notifier_update_name(Efl_Net_Session_Data *pd, Eldbus_Message_Iter *var)
{
const char *str;
if (!eldbus_message_iter_arguments_get(var, "s", &str))
return EINVAL;
eina_stringshare_replace(&pd->name, str);
return 0;
}
static Eina_Error
_efl_net_session_notifier_update_technology(Efl_Net_Session_Data *pd, Eldbus_Message_Iter *var)
{
const char *str;
if (!eldbus_message_iter_arguments_get(var, "s", &str))
return EINVAL;
pd->technology = 0;
if (!_efl_net_session_technology_from_str(str, &pd->technology))
return EINVAL;
return 0;
}
static Eina_Error
_efl_net_session_notifier_update_interface(Efl_Net_Session_Data *pd, Eldbus_Message_Iter *var)
{
const char *str;
if (!eldbus_message_iter_arguments_get(var, "s", &str))
return EINVAL;
eina_stringshare_replace(&pd->interface, str);
return 0;
}
static Eina_Error
_efl_net_session_notifier_update_ipv4(Efl_Net_Session_Data *pd, Eldbus_Message_Iter *var)
{
Eldbus_Message_Iter *sub, *entry;
if (!eldbus_message_iter_arguments_get(var, "a{sv}", &sub))
return EINVAL;
while (eldbus_message_iter_get_and_next(sub, 'e', &entry))
{
const char *key;
Eldbus_Message_Iter *value;
if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &value))
{
ERR("Unexpected dict entry signature: %s", eldbus_message_iter_signature_get(entry));
continue;
}
if (strcmp(key, "Method") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
DBG("configuration method %s", str);
}
else if (strcmp(key, "Address") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
{
DBG("address %s", str);
eina_stringshare_replace(&pd->ipv4.address, str);
}
}
else if (strcmp(key, "Gateway") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
{
DBG("gateway %s", str);
eina_stringshare_replace(&pd->ipv4.gateway, str);
}
}
else if (strcmp(key, "Netmask") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
{
DBG("netmask %s", str);
eina_stringshare_replace(&pd->ipv4.netmask, str);
}
}
else
{
WRN("Unsupported field %s (signature=%s)", key, eldbus_message_iter_signature_get(value));
continue;
}
}
return 0;
}
static Eina_Error
_efl_net_session_notifier_update_ipv6(Efl_Net_Session_Data *pd, Eldbus_Message_Iter *var)
{
Eldbus_Message_Iter *sub, *entry;
if (!eldbus_message_iter_arguments_get(var, "a{sv}", &sub))
return EINVAL;
while (eldbus_message_iter_get_and_next(sub, 'e', &entry))
{
const char *key;
Eldbus_Message_Iter *value;
if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &value))
{
ERR("Unexpected dict entry signature: %s", eldbus_message_iter_signature_get(entry));
continue;
}
if (strcmp(key, "Method") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
DBG("configuration method %s", str);
}
else if (strcmp(key, "Address") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
{
DBG("address %s", str);
eina_stringshare_replace(&pd->ipv6.address, str);
}
}
else if (strcmp(key, "Gateway") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
{
DBG("gateway %s", str);
eina_stringshare_replace(&pd->ipv6.gateway, str);
}
}
else if (strcmp(key, "Netmask") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
{
DBG("netmask %s", str);
eina_stringshare_replace(&pd->ipv6.netmask, str);
}
}
else if (strcmp(key, "PrefixLength") == 0)
{
if (!eldbus_message_iter_arguments_get(value, "y", &pd->ipv6.prefix_length))
ERR("expected unsigned byte, property=%s", key);
else
DBG("prefix_length %hhu", pd->ipv6.prefix_length);
}
else if (strcmp(key, "Privacy") == 0)
{
const char *str;
if (!eldbus_message_iter_arguments_get(value, "s", &str))
ERR("expected string, property=%s", key);
else
DBG("privacy %s (unused)", str);
}
else
{
WRN("Unsupported field %s (signature=%s)", key, eldbus_message_iter_signature_get(value));
continue;
}
}
return 0;
}
static Eina_Error
_efl_net_session_notifier_update_bearers(Efl_Net_Session_Data *pd EINA_UNUSED, Eldbus_Message_Iter *var)
{
Eldbus_Message_Iter *sub;
const char *str;
if (!eldbus_message_iter_arguments_get(var, "as", &sub))
{
ERR("Expected array of strings, got %s", eldbus_message_iter_signature_get(var));
return EINVAL;
}
while (eldbus_message_iter_get_and_next(sub, 's', &str))
DBG("allowed bearer '%s'", str);
return 0;
}
static Eina_Error
_efl_net_session_notifier_update_connection_type(Efl_Net_Session_Data *pd EINA_UNUSED, Eldbus_Message_Iter *var)
{
const char *str;
if (!eldbus_message_iter_arguments_get(var, "s", &str))
return EINVAL;
DBG("connection type '%s'", str);
return 0;
}
/* step #4: get the initial state and changed applied locally */
static Eldbus_Message *
_efl_net_session_notifier_update(const Eldbus_Service_Interface *service, const Eldbus_Message *msg)
{
Eo *o = eldbus_service_object_data_get(service, "efl_net");
Efl_Net_Session_Data *pd = efl_data_scope_get(o, MY_CLASS);
Eldbus_Message_Iter *array, *entry;
Eina_Bool updated = EINA_FALSE;
DBG("Session %p is updated %s", o, eldbus_message_path_get(msg));
EINA_SAFETY_ON_NULL_GOTO(o, end);
if (!eldbus_message_arguments_get(msg, "a{sv}", &array))
{
ERR("Unexpected net.connman.Notifier.Update() signature %s", eldbus_message_signature_get(msg));
goto end;
}
while (eldbus_message_iter_get_and_next(array, 'e', &entry))
{
const char *key;
Eldbus_Message_Iter *var;
Eina_Error err;
if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var))
{
ERR("Unexpected dict entry signature: %s", eldbus_message_iter_signature_get(entry));
continue;
}
if (strcmp(key, "State") == 0)
err = _efl_net_session_notifier_update_state(pd, var);
else if (strcmp(key, "Name") == 0)
err = _efl_net_session_notifier_update_name(pd, var);
else if (strcmp(key, "Bearer") == 0)
err = _efl_net_session_notifier_update_technology(pd, var);
else if (strcmp(key, "Interface") == 0)
err = _efl_net_session_notifier_update_interface(pd, var);
else if (strcmp(key, "IPv4") == 0)
err = _efl_net_session_notifier_update_ipv4(pd, var);
else if (strcmp(key, "IPv6") == 0)
err = _efl_net_session_notifier_update_ipv6(pd, var);
else if (strcmp(key, "AllowedBearers") == 0)
err = _efl_net_session_notifier_update_bearers(pd, var);
else if (strcmp(key, "ConnectionType") == 0)
err = _efl_net_session_notifier_update_connection_type(pd, var);
else
{
WRN("Unsupported setting %s (signature=%s)", key, eldbus_message_iter_signature_get(var));
continue;
}
if (err)
{
ERR("Could not handle property %s: %s", key, eina_error_msg_get(err));
continue;
}
updated |= EINA_TRUE;
}
if (updated) efl_event_callback_call(o, EFL_NET_SESSION_EVENT_CHANGED, NULL);
end:
return eldbus_message_method_return_new(msg);
}
static const Eldbus_Service_Interface_Desc _efl_net_session_notifier_desc = {
.interface = "net.connman.Notification",
.methods = (const Eldbus_Method []){
{
.member = "Release",
.in = NULL,
.out = NULL,
.cb = _efl_net_session_notifier_release,
.flags = 0
},
{
.member = "Update",
.in = ELDBUS_ARGS({"a{sv}", "settings"}),
.out = NULL,
.cb = _efl_net_session_notifier_update,
.flags = 0
},
{ NULL, NULL, NULL, NULL, 0 }
},
.signals = NULL,
.properties = NULL,
.default_get = NULL,
.default_set = NULL
};
/* return of step #2: session was created, get a proxy for it */
static void
_efl_net_session_create_session_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
Eo *o = data;
Efl_Net_Session_Data *pd = efl_data_scope_get(o, MY_CLASS);
Eldbus_Connection *conn;
Eldbus_Object *obj;
const char *err_name, *err_msg, *path;
if (pd->mgr_pending == pending)
pd->mgr_pending = NULL;
if (eldbus_message_error_get(msg, &err_name, &err_msg))
{
ERR("Could not create session %p: %s=%s", o, err_name, err_msg);
return;
}
if (!eldbus_message_arguments_get(msg, "o", &path))
{
ERR("Could not get session %p DBus path!", o);
return;
}
conn = efl_net_connman_connection_get();
obj = eldbus_object_get(conn, "net.connman", path);
pd->proxy = eldbus_proxy_get(obj, "net.connman.Session");
if (!pd->proxy)
{
ERR("could not create DBus proxy for interface='net.connman.Session', name='net.connman', path='%s' o=%p", path, o);
eldbus_object_unref(obj);
return;
}
DBG("Created session %p (session=%s) with ConnMan...", o, path);
if (pd->connect.connected)
{
DBG("apply pending connect request: online_required=%d, technologies_allowed=%#x", pd->connect.online_required, pd->connect.technologies_allowed);
_efl_net_session_connect_do(o, pd);
}
}
static void
_efl_net_session_clear(Efl_Net_Session_Data *pd)
{
eina_stringshare_replace(&pd->name, NULL);
eina_stringshare_replace(&pd->interface, NULL);
eina_stringshare_replace(&pd->ipv4.address, NULL);
eina_stringshare_replace(&pd->ipv4.netmask, NULL);
eina_stringshare_replace(&pd->ipv4.gateway, NULL);
eina_stringshare_replace(&pd->ipv6.address, NULL);
eina_stringshare_replace(&pd->ipv6.netmask, NULL);
eina_stringshare_replace(&pd->ipv6.gateway, NULL);
pd->ipv6.prefix_length = 0;
pd->state = EFL_NET_SESSION_STATE_OFFLINE;
pd->technology = EFL_NET_SESSION_TECHNOLOGY_UNKNOWN;
}
/* step #2: once connman is there, call CreateSession */
static void
_efl_net_session_connman_name_owner_changed(void *data, const char *bus, const char *old_id, const char *new_id)
{
Eo *o = data;
Efl_Net_Session_Data *pd = efl_data_scope_get(o, MY_CLASS);
Eldbus_Message_Iter *msg_itr, *cont;
Eldbus_Proxy *mgr;
Eldbus_Message *msg;
const char *path;
DBG("Name Owner Changed %s: %s->%s", bus, old_id, new_id);
if ((!new_id) || (new_id[0] == '\0'))
{
/* connman is gone, remove proxy as it became useless */
if (pd->proxy)
{
Eldbus_Object *obj = eldbus_proxy_object_get(pd->proxy);
eldbus_proxy_unref(pd->proxy);
pd->proxy = NULL;
eldbus_object_unref(obj);
}
_efl_net_session_clear(pd);
efl_event_callback_call(o, EFL_NET_SESSION_EVENT_CHANGED, NULL);
return;
}
path = eldbus_service_object_path_get(pd->notifier);
EINA_SAFETY_ON_NULL_RETURN(path);
INF("Create session %p notifier=%s with %s (%s)", o, path, bus, new_id);
mgr = efl_net_connman_manager_get();
EINA_SAFETY_ON_NULL_RETURN(mgr);
msg = eldbus_proxy_method_call_new(mgr, "CreateSession");
EINA_SAFETY_ON_NULL_RETURN(msg);
msg_itr = eldbus_message_iter_get(msg);
EINA_SAFETY_ON_NULL_GOTO(msg_itr, error_send);
cont = eldbus_message_iter_container_new(msg_itr, 'a', "{sv}");
eldbus_message_iter_container_close(msg_itr, cont); /* empty, use defaults */
eldbus_message_iter_basic_append(msg_itr, 'o', path);
if (pd->mgr_pending)
eldbus_pending_cancel(pd->mgr_pending);
pd->mgr_pending = eldbus_proxy_send(mgr, msg, _efl_net_session_create_session_cb, o, DEFAULT_TIMEOUT);
EINA_SAFETY_ON_NULL_GOTO(pd->mgr_pending, error_send);
return;
error_send:
eldbus_message_unref(msg);
}
EOLIAN static Eo *
_efl_net_session_efl_object_constructor(Eo *o, Efl_Net_Session_Data *pd EINA_UNUSED)
{
if (!efl_net_connman_init())
{
ERR("could not initialize connman infrastructure");
return NULL;
}
return efl_constructor(efl_super(o, MY_CLASS));
}
EOLIAN static Eo *
_efl_net_session_efl_object_finalize(Eo *o, Efl_Net_Session_Data *pd)
{
Eldbus_Connection *conn;
char path[128];
o = efl_finalize(efl_super(o, MY_CLASS));
if (!o) return NULL;
conn = efl_net_connman_connection_get();
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
/* step #1: create local notifier path */
snprintf(path, sizeof(path), "/connman/notifier_%p", o);
pd->notifier = eldbus_service_interface_register(conn, path, &_efl_net_session_notifier_desc);
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->notifier, NULL);
eldbus_service_object_data_set(pd->notifier, "efl_net", o);
eldbus_name_owner_changed_callback_add(conn, "net.connman", _efl_net_session_connman_name_owner_changed, o, EINA_TRUE);
DBG("waiting for net.connman to show on the DBus system bus...");
return o;
}
EOLIAN static void
_efl_net_session_efl_object_destructor(Eo *o, Efl_Net_Session_Data *pd)
{
Eldbus_Connection *conn;
conn = efl_net_connman_connection_get();
eldbus_name_owner_changed_callback_del(conn, "net.connman", _efl_net_session_connman_name_owner_changed, o);
if (pd->mgr_pending)
{
eldbus_pending_cancel(pd->mgr_pending);
pd->mgr_pending = NULL;
}
if (pd->notifier)
{
eldbus_service_object_data_del(pd->notifier, "efl_net");
eldbus_service_object_unregister(pd->notifier);
pd->notifier = NULL;
}
if (pd->proxy)
{
Eldbus_Object *obj = eldbus_proxy_object_get(pd->proxy);
Eldbus_Proxy *mgr = efl_net_connman_manager_get();
/* DestroySession is required since the manager proxy and bus
* may be alive, thus connman won't get any NameOwnerChanged
* or related to know the object is gone
*/
eldbus_proxy_call(mgr, "DestroySession", NULL, NULL, DEFAULT_TIMEOUT,
"o", eldbus_object_path_get(obj));
eldbus_proxy_unref(pd->proxy);
eldbus_object_unref(obj);
pd->proxy = NULL;
}
_efl_net_session_clear(pd);
efl_destructor(efl_super(o, MY_CLASS));
efl_net_connman_shutdown();
}
EOLIAN static const char *
_efl_net_session_network_name_get(const Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
{
return pd->name;
}
EOLIAN static Efl_Net_Session_State
_efl_net_session_state_get(const Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
{
return pd->state;
}
EOLIAN static Efl_Net_Session_Technology
_efl_net_session_technology_get(const Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
{
return pd->technology;
}
EOLIAN static const char *
_efl_net_session_interface_get(const Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
{
return pd->interface;
}
EOLIAN static void
_efl_net_session_ipv4_get(const Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd, const char **address, const char **netmask, const char **gateway)
{
if (address) *address = pd->ipv4.address;
if (netmask) *netmask = pd->ipv4.netmask;
if (gateway) *gateway = pd->ipv4.gateway;
}
EOLIAN static void
_efl_net_session_ipv6_get(const Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd, const char **address, uint8_t *prefix_length, const char **netmask, const char **gateway)
{
if (address) *address = pd->ipv6.address;
if (netmask) *netmask = pd->ipv6.netmask;
if (gateway) *gateway = pd->ipv6.gateway;
if (prefix_length) *prefix_length = pd->ipv6.prefix_length;
}
static void
_efl_net_session_connect_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
Eo *o = data;
Efl_Net_Session_Data *pd = efl_data_scope_get(o, MY_CLASS);
const char *err_name, *err_msg;
if (pd->connect.pending == pending)
pd->connect.pending = NULL;
if (eldbus_message_error_get(msg, &err_name, &err_msg))
{
WRN("Could not Connect: %s=%s", err_name, err_msg);
return;
}
DBG("Successfully requested a connection online_required=%hhu, technologies_allowed=%#x", pd->connect.online_required, pd->connect.technologies_allowed);
}
static void
_efl_net_session_connect_do_connect(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
Eo *o = data;
Efl_Net_Session_Data *pd = efl_data_scope_get(o, MY_CLASS);
const char *err_name, *err_msg;
if (pd->connect.pending == pending)
pd->connect.pending = NULL;
if (eldbus_message_error_get(msg, &err_name, &err_msg))
{
WRN("Could not Change('ConnectionType'): %s=%s", err_name, err_msg);
return;
}
pd->connect.pending = eldbus_proxy_call(pd->proxy, "Connect",
_efl_net_session_connect_cb, o,
DEFAULT_TIMEOUT, "");
EINA_SAFETY_ON_NULL_RETURN(pd->connect.pending);
}
static void
_efl_net_session_connect_change_online_required(void *data, const Eldbus_Message *msg_ret, Eldbus_Pending *pending)
{
Eo *o = data;
Efl_Net_Session_Data *pd = efl_data_scope_get(o, MY_CLASS);
Eldbus_Message *msg;
Eldbus_Message_Iter *msg_itr, *itr;
const char *err_name, *err_msg;
Eina_Bool ret;
if (pd->connect.pending == pending)
pd->connect.pending = NULL;
if (eldbus_message_error_get(msg_ret, &err_name, &err_msg))
{
WRN("Could not Change('AllowedBearers'): %s=%s", err_name, err_msg);
return;
}
msg = eldbus_proxy_method_call_new(pd->proxy, "Change");
EINA_SAFETY_ON_NULL_RETURN(msg);
msg_itr = eldbus_message_iter_get(msg);
EINA_SAFETY_ON_NULL_GOTO(msg_itr, error_msg);
eldbus_message_iter_basic_append(msg_itr, 's', "ConnectionType");
itr = eldbus_message_iter_container_new(msg_itr, 'v', "s");
EINA_SAFETY_ON_NULL_GOTO(itr, error_msg);
ret = eldbus_message_iter_basic_append(itr, 's', pd->connect.online_required ? "internet" : "local");
EINA_SAFETY_ON_FALSE_GOTO(ret, error_msg);
eldbus_message_iter_container_close(msg_itr, itr);
pd->connect.pending = eldbus_proxy_send(pd->proxy, msg,
_efl_net_session_connect_do_connect, o,
DEFAULT_TIMEOUT);
EINA_SAFETY_ON_NULL_RETURN(pd->connect.pending);
return;
error_msg:
eldbus_message_unref(msg);
}
static void
_efl_net_session_connect_do(Eo *o, Efl_Net_Session_Data *pd)
{
Eldbus_Message_Iter *msg_itr, *itr, *array;
Eldbus_Message *msg;
if (!pd->connect.connected) return;
if (pd->connect.pending)
{
eldbus_pending_cancel(pd->connect.pending);
pd->connect.pending = NULL;
}
msg = eldbus_proxy_method_call_new(pd->proxy, "Change");
EINA_SAFETY_ON_NULL_RETURN(msg);
msg_itr = eldbus_message_iter_get(msg);
EINA_SAFETY_ON_NULL_GOTO(msg_itr, error_msg);
eldbus_message_iter_basic_append(msg_itr, 's', "AllowedBearers");
itr = eldbus_message_iter_container_new(msg_itr, 'v', "as");
EINA_SAFETY_ON_NULL_GOTO(itr, error_msg);
array = eldbus_message_iter_container_new(itr, 'a', "s");
#define MAP(X, s) \
if ((pd->connect.technologies_allowed & EFL_NET_SESSION_TECHNOLOGY_ ## X) == EFL_NET_SESSION_TECHNOLOGY_ ## X) \
eldbus_message_iter_basic_append(array, 's', s)
MAP(ALL, "*");
if (pd->connect.technologies_allowed == EFL_NET_SESSION_TECHNOLOGY_ALL) goto end;
MAP(ETHERNET, "ethernet");
MAP(WIFI, "wifi");
MAP(BLUETOOTH, "bluetooth");
MAP(CELLULAR, "cellular");
MAP(VPN, "vpn");
MAP(GADGET, "gadget");
#undef MAP
end:
eldbus_message_iter_container_close(itr, array);
eldbus_message_iter_container_close(msg_itr, itr);
pd->connect.pending = eldbus_proxy_send(pd->proxy, msg,
_efl_net_session_connect_change_online_required, o,
DEFAULT_TIMEOUT);
EINA_SAFETY_ON_NULL_RETURN(pd->connect.pending);
return;
error_msg:
eldbus_message_unref(msg);
}
EOLIAN static void
_efl_net_session_connect(Eo *o, Efl_Net_Session_Data *pd, Eina_Bool online_required, Efl_Net_Session_Technology technologies_allowed)
{
pd->connect.connected = EINA_TRUE;
pd->connect.online_required = online_required;
pd->connect.technologies_allowed = technologies_allowed;
if (pd->proxy) _efl_net_session_connect_do(o, pd);
}
EOLIAN static void
_efl_net_session_disconnect(Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
{
if (pd->connect.pending)
{
eldbus_pending_cancel(pd->connect.pending);
pd->connect.pending = NULL;
}
pd->connect.connected = EINA_FALSE;
eldbus_proxy_call(pd->proxy, "Disconnect", NULL, NULL, DEFAULT_TIMEOUT, "");
}
#include "efl_net_session.eo.c"