forked from enlightenment/efl
efl_net_session and efl_net_control for ConnMan
These are objects to allow control of networking devices (efl_net_control) as well as an application to request for connectivity (efl_net_session). They are loosely based on ConnMan.org, which we already use in Enlightenment Window Manager via DBus access with Eldbus. However they do not map 1:1 as the goal was to expose a viable subset of controls but in a simple and general way, thus nome strings were converted to enums, some arrays of strings were converted to bitwise flags, some names were made more general, such as "service" was turned into "access point" so it doesn't generate confusion with other "network services" (ie: http server), or "favorite" that was renamed to "remembered". Some behavior are slightly different (yet able to be implemented on top), such as "Service.MoveBefore" and "MoveAfter" were converted to a numeric "priority", calculated from service's list index, changing the priority will reoder the list and thus generate the MoveBefore and MoveAfter DBus commands. ConnMan was chosen not only because we already use it, but because its DBus API is sane and simple, with the server doing almost all that we need. This is visible in the efl_net_session, which is completely done in the server and do not require any extra work on our side -- aside from talking DBus and converting to Eo, which is a major work :-D NOTE: ConnMan doesn't use FreeDesktop.Org DBus interfaces such as Properties and ObjectManager, thus we cannot use eldbus_model_object. There are two examples added: - efl_net_session_example: monitors the connection available for an application and try to connect. You need a connman compiled with session_policy_local and a configuration file explained in https://github.com/aldebaran/connman/blob/master/doc/session-policy-format.txt to get a connection if nothing is connected. Otherwise it will just monitor the connectivity state. - efl_net_control_example: monitors, plays the agent and configure the network details. It can enable/disable technologies, connect to access points (services) and configure them. It's quite extensive as allows testing all of ConnMan's DBus API except P2P (Peers).
This commit is contained in:
parent
5e53ecb9e6
commit
98fe627ca4
|
@ -3052,6 +3052,7 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [eet])
|
||||||
EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [eina])
|
EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [eina])
|
||||||
EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [ecore])
|
EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [ecore])
|
||||||
EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [emile])
|
EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [emile])
|
||||||
|
EFL_INTERNAL_DEPEND_PKG([ECORE_CON], [eldbus])
|
||||||
|
|
||||||
EFL_ADD_LIBS([ECORE_CON], [-lm])
|
EFL_ADD_LIBS([ECORE_CON], [-lm])
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,10 @@ ecore_con_eolian_files = \
|
||||||
lib/ecore_con/efl_net_ssl_context.eo \
|
lib/ecore_con/efl_net_ssl_context.eo \
|
||||||
lib/ecore_con/efl_net_dialer_ssl.eo \
|
lib/ecore_con/efl_net_dialer_ssl.eo \
|
||||||
lib/ecore_con/efl_net_server_ssl.eo \
|
lib/ecore_con/efl_net_server_ssl.eo \
|
||||||
|
lib/ecore_con/efl_net_control_access_point.eo \
|
||||||
|
lib/ecore_con/efl_net_control_technology.eo \
|
||||||
|
lib/ecore_con/efl_net_control.eo \
|
||||||
|
lib/ecore_con/efl_net_session.eo \
|
||||||
lib/ecore_con/ecore_con_eet_base.eo \
|
lib/ecore_con/ecore_con_eet_base.eo \
|
||||||
lib/ecore_con/ecore_con_eet_server_obj.eo \
|
lib/ecore_con/ecore_con_eet_server_obj.eo \
|
||||||
lib/ecore_con/ecore_con_eet_client_obj.eo \
|
lib/ecore_con/ecore_con_eet_client_obj.eo \
|
||||||
|
@ -104,7 +108,13 @@ lib/ecore_con/efl_net_server_udp_client.c \
|
||||||
lib/ecore_con/efl_net_socket_ssl.c \
|
lib/ecore_con/efl_net_socket_ssl.c \
|
||||||
lib/ecore_con/efl_net_ssl_context.c \
|
lib/ecore_con/efl_net_ssl_context.c \
|
||||||
lib/ecore_con/efl_net_dialer_ssl.c \
|
lib/ecore_con/efl_net_dialer_ssl.c \
|
||||||
lib/ecore_con/efl_net_server_ssl.c
|
lib/ecore_con/efl_net_server_ssl.c \
|
||||||
|
lib/ecore_con/efl_net-connman.h \
|
||||||
|
lib/ecore_con/efl_net-connman.c \
|
||||||
|
lib/ecore_con/efl_net_control_access_point-connman.c \
|
||||||
|
lib/ecore_con/efl_net_control_technology-connman.c \
|
||||||
|
lib/ecore_con/efl_net_control-connman.c \
|
||||||
|
lib/ecore_con/efl_net_session-connman.c
|
||||||
|
|
||||||
EXTRA_DIST2 += lib/ecore_con/ecore_con_legacy.c
|
EXTRA_DIST2 += lib/ecore_con/ecore_con_legacy.c
|
||||||
|
|
||||||
|
|
|
@ -61,3 +61,5 @@
|
||||||
/efl_net_socket_ssl_dialer_example
|
/efl_net_socket_ssl_dialer_example
|
||||||
/efl_net_socket_ssl_server_example
|
/efl_net_socket_ssl_server_example
|
||||||
/*.pem
|
/*.pem
|
||||||
|
/efl_net_session_example
|
||||||
|
/efl_net_control_example
|
||||||
|
|
|
@ -88,7 +88,9 @@ efl_net_dialer_websocket_example \
|
||||||
efl_net_dialer_websocket_autobahntestee \
|
efl_net_dialer_websocket_autobahntestee \
|
||||||
efl_net_dialer_udp_example \
|
efl_net_dialer_udp_example \
|
||||||
efl_net_socket_ssl_dialer_example \
|
efl_net_socket_ssl_dialer_example \
|
||||||
efl_net_socket_ssl_server_example
|
efl_net_socket_ssl_server_example \
|
||||||
|
efl_net_session_example \
|
||||||
|
efl_net_control_example
|
||||||
|
|
||||||
|
|
||||||
ECORE_COMMON_LDADD = \
|
ECORE_COMMON_LDADD = \
|
||||||
|
@ -334,6 +336,12 @@ efl_net_socket_ssl_dialer_example_LDADD = $(ECORE_CON_COMMON_LDADD)
|
||||||
efl_net_socket_ssl_server_example_SOURCES = efl_net_socket_ssl_server_example.c
|
efl_net_socket_ssl_server_example_SOURCES = efl_net_socket_ssl_server_example.c
|
||||||
efl_net_socket_ssl_server_example_LDADD = $(ECORE_CON_COMMON_LDADD)
|
efl_net_socket_ssl_server_example_LDADD = $(ECORE_CON_COMMON_LDADD)
|
||||||
|
|
||||||
|
efl_net_session_example_SOURCES = efl_net_session_example.c
|
||||||
|
efl_net_session_example_LDADD = $(ECORE_CON_COMMON_LDADD)
|
||||||
|
|
||||||
|
efl_net_control_example_SOURCES = efl_net_control_example.c
|
||||||
|
efl_net_control_example_LDADD = $(ECORE_CON_COMMON_LDADD)
|
||||||
|
|
||||||
SRCS = \
|
SRCS = \
|
||||||
ecore_animator_example.c \
|
ecore_animator_example.c \
|
||||||
ecore_buffer_example.c \
|
ecore_buffer_example.c \
|
||||||
|
@ -391,7 +399,9 @@ efl_net_dialer_websocket_example.c \
|
||||||
efl_net_dialer_websocket_autobahntestee.c \
|
efl_net_dialer_websocket_autobahntestee.c \
|
||||||
efl_net_dialer_udp_example.c \
|
efl_net_dialer_udp_example.c \
|
||||||
efl_net_socket_ssl_dialer_example.c \
|
efl_net_socket_ssl_dialer_example.c \
|
||||||
efl_net_socket_ssl_server_example.c
|
efl_net_socket_ssl_server_example.c \
|
||||||
|
efl_net_session_example.c \
|
||||||
|
efl_net_control_example.c
|
||||||
|
|
||||||
%.pem:
|
%.pem:
|
||||||
echo -e "US\nOR\nPortland\nXPTO Ltd\n\nlocalhost\nroot@localhost\n" | openssl req -new -x509 -days 30 -nodes -out $@ -keyout $@
|
echo -e "US\nOR\nPortland\nXPTO Ltd\n\nlocalhost\nroot@localhost\n" | openssl req -new -x509 -days 30 -nodes -out $@ -keyout $@
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,181 @@
|
||||||
|
#define EFL_BETA_API_SUPPORT 1
|
||||||
|
#define EFL_EO_API_SUPPORT 1
|
||||||
|
#include <Ecore.h>
|
||||||
|
#include <Ecore_Con.h>
|
||||||
|
#include <Ecore_Getopt.h>
|
||||||
|
|
||||||
|
static int retval = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
_state_str(Efl_Net_Session_State state)
|
||||||
|
{
|
||||||
|
static const char *strs[] = {
|
||||||
|
[EFL_NET_SESSION_STATE_OFFLINE] = "offline",
|
||||||
|
[EFL_NET_SESSION_STATE_LOCAL] = "local",
|
||||||
|
[EFL_NET_SESSION_STATE_ONLINE] = "online",
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((unsigned)state > sizeof(strs)/sizeof(strs[0])) return "???";
|
||||||
|
if (!strs[state]) return "???";
|
||||||
|
return strs[state];
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
_technology_str(Efl_Net_Session_Technology tech)
|
||||||
|
{
|
||||||
|
static const char *strs[] = {
|
||||||
|
[EFL_NET_SESSION_TECHNOLOGY_UNKNOWN] = "none",
|
||||||
|
[EFL_NET_SESSION_TECHNOLOGY_ETHERNET] = "ethernet",
|
||||||
|
[EFL_NET_SESSION_TECHNOLOGY_WIFI] = "wifi",
|
||||||
|
[EFL_NET_SESSION_TECHNOLOGY_BLUETOOTH] = "bluetooth",
|
||||||
|
[EFL_NET_SESSION_TECHNOLOGY_CELLULAR] = "cellular",
|
||||||
|
[EFL_NET_SESSION_TECHNOLOGY_VPN] = "vpn",
|
||||||
|
[EFL_NET_SESSION_TECHNOLOGY_GADGET] = "gadget",
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((unsigned)tech > sizeof(strs)/sizeof(strs[0])) return "???";
|
||||||
|
if (!strs[tech]) return "???";
|
||||||
|
return strs[tech];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_changed(void *data EINA_UNUSED, const Efl_Event *event)
|
||||||
|
{
|
||||||
|
Eo *session = event->object;
|
||||||
|
const char *ip, *netmask, *gateway;
|
||||||
|
uint8_t prefix;
|
||||||
|
|
||||||
|
printf("INFO: session changed:\n"
|
||||||
|
"INFO: - name: '%s'\n"
|
||||||
|
"INFO: - state: %s\n"
|
||||||
|
"INFO: - technology: %s\n"
|
||||||
|
"INFO: - interface: '%s'\n",
|
||||||
|
efl_net_session_name_get(session),
|
||||||
|
_state_str(efl_net_session_state_get(session)),
|
||||||
|
_technology_str(efl_net_session_technology_get(session)),
|
||||||
|
efl_net_session_interface_get(session));
|
||||||
|
|
||||||
|
efl_net_session_ipv4_get(session, &ip, &netmask, &gateway);
|
||||||
|
if (ip)
|
||||||
|
{
|
||||||
|
printf("INFO: - IPv4: %s, gateway=%s, netmask=%s\n",
|
||||||
|
ip, gateway, netmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
efl_net_session_ipv6_get(session, &ip, &prefix, &netmask, &gateway);
|
||||||
|
if (ip)
|
||||||
|
{
|
||||||
|
printf("INFO: - IPv6: %s/%hhu, gateway=%s, netmask=%s\n",
|
||||||
|
ip, prefix, gateway, netmask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EFL_CALLBACKS_ARRAY_DEFINE(session_events_cbs,
|
||||||
|
{ EFL_NET_SESSION_EVENT_CHANGED, _changed });
|
||||||
|
|
||||||
|
static const Ecore_Getopt options = {
|
||||||
|
"efl_net_session_example", /* program name */
|
||||||
|
NULL, /* usage line */
|
||||||
|
"1", /* version */
|
||||||
|
"(C) 2016 Enlightenment Project", /* copyright */
|
||||||
|
"BSD 2-Clause", /* license */
|
||||||
|
/* long description, may be multiline and contain \n */
|
||||||
|
"Example of Efl_Net_Session to request or monitor a network session for an application.\n",
|
||||||
|
EINA_FALSE,
|
||||||
|
{
|
||||||
|
ECORE_GETOPT_STORE_TRUE('c', "connect", "Require a connection to the internet (See -o/--require-online)."),
|
||||||
|
ECORE_GETOPT_STORE_TRUE('o', "require-online", "When connecting (-c/--connect), require connection to the internet. Otherwise a local network connection is enough"),
|
||||||
|
ECORE_GETOPT_APPEND('t', "technology", "Bearer technologies to use when connecting (ethernet, wifi, bluetooth, cellular, vpn, gadget or all)", ECORE_GETOPT_TYPE_STR),
|
||||||
|
|
||||||
|
ECORE_GETOPT_VERSION('V', "version"),
|
||||||
|
ECORE_GETOPT_COPYRIGHT('C', "copyright"),
|
||||||
|
ECORE_GETOPT_LICENSE('L', "license"),
|
||||||
|
ECORE_GETOPT_HELP('h', "help"),
|
||||||
|
ECORE_GETOPT_SENTINEL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
Eina_List *techs = NULL;
|
||||||
|
Eina_Bool do_connect = EINA_FALSE;
|
||||||
|
Eina_Bool require_online = EINA_FALSE;
|
||||||
|
Eina_Bool quit_option = EINA_FALSE;
|
||||||
|
Efl_Net_Session_Technology technologies = EFL_NET_SESSION_TECHNOLOGY_ALL;
|
||||||
|
Ecore_Getopt_Value values[] = {
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(do_connect),
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(require_online),
|
||||||
|
ECORE_GETOPT_VALUE_LIST(techs),
|
||||||
|
|
||||||
|
/* standard block to provide version, copyright, license and help */
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -V/--version quits */
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -C/--copyright quits */
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -L/--license quits */
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(quit_option), /* -h/--help quits */
|
||||||
|
ECORE_GETOPT_VALUE_NONE /* sentinel */
|
||||||
|
};
|
||||||
|
int args;
|
||||||
|
Eo *session;
|
||||||
|
|
||||||
|
ecore_init();
|
||||||
|
ecore_con_init();
|
||||||
|
|
||||||
|
args = ecore_getopt_parse(&options, values, argc, argv);
|
||||||
|
if (args < 0)
|
||||||
|
{
|
||||||
|
fputs("ERROR: Could not parse command line options.\n", stderr);
|
||||||
|
retval = EXIT_FAILURE;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quit_option) goto end;
|
||||||
|
|
||||||
|
if (techs)
|
||||||
|
{
|
||||||
|
technologies = 0;
|
||||||
|
EINA_LIST_FREE(techs, str)
|
||||||
|
{
|
||||||
|
if (0) {}
|
||||||
|
#define MAP(X) else if (strcasecmp(str, #X) == 0) technologies |= EFL_NET_SESSION_TECHNOLOGY_ ## X
|
||||||
|
MAP(ETHERNET);
|
||||||
|
MAP(WIFI);
|
||||||
|
MAP(BLUETOOTH);
|
||||||
|
MAP(CELLULAR);
|
||||||
|
MAP(VPN);
|
||||||
|
MAP(GADGET);
|
||||||
|
#undef MAP
|
||||||
|
else fprintf(stderr, "WARNING: unknown technology '%s' ignored.\n", str);
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session = efl_add(EFL_NET_SESSION_CLASS, ecore_main_loop_get(),
|
||||||
|
efl_event_callback_array_add(efl_added, session_events_cbs(), NULL));
|
||||||
|
if (!session)
|
||||||
|
{
|
||||||
|
fputs("ERROR: Could not create Efl.Net.Session object.\n", stderr);
|
||||||
|
retval = EXIT_FAILURE;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_connect)
|
||||||
|
{
|
||||||
|
printf("INFO: requesting a %s connection.\n", require_online ? "online" : "local");
|
||||||
|
efl_net_session_connect(session, require_online, technologies);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("INFO: the session will active while this application runs. Use ^C (Control + C) to close it\n");
|
||||||
|
|
||||||
|
ecore_main_loop_begin();
|
||||||
|
|
||||||
|
efl_del(session);
|
||||||
|
|
||||||
|
end:
|
||||||
|
ecore_con_shutdown();
|
||||||
|
ecore_shutdown();
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
|
@ -32,10 +32,14 @@
|
||||||
#include "efl_net_dialer_http.eo.h"
|
#include "efl_net_dialer_http.eo.h"
|
||||||
#include "efl_net_dialer_websocket.eo.h"
|
#include "efl_net_dialer_websocket.eo.h"
|
||||||
|
|
||||||
|
|
||||||
#include "efl_net_ssl_types.eot.h"
|
#include "efl_net_ssl_types.eot.h"
|
||||||
|
|
||||||
#include "efl_net_ssl_context.eo.h"
|
#include "efl_net_ssl_context.eo.h"
|
||||||
#include "efl_net_socket_ssl.eo.h"
|
#include "efl_net_socket_ssl.eo.h"
|
||||||
#include "efl_net_dialer_ssl.eo.h"
|
#include "efl_net_dialer_ssl.eo.h"
|
||||||
#include "efl_net_server_ssl.eo.h"
|
#include "efl_net_server_ssl.eo.h"
|
||||||
|
|
||||||
|
#include "efl_net_control_technology.eo.h"
|
||||||
|
#include "efl_net_control_access_point.eo.h"
|
||||||
|
#include "efl_net_control.eo.h"
|
||||||
|
#include "efl_net_session.eo.h"
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "efl_net-connman.h"
|
||||||
|
|
||||||
|
static Eldbus_Proxy *_efl_net_connman_manager;
|
||||||
|
static Eldbus_Connection *_efl_net_connman_conn;
|
||||||
|
static int _efl_net_connman_init_count;
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_connman_manager_free(void *data EINA_UNUSED, const void *dead_ptr)
|
||||||
|
{
|
||||||
|
DBG("ConnMan Manager was freed");
|
||||||
|
|
||||||
|
/* handle programming errors where 'too many unrefs' happen */
|
||||||
|
if (dead_ptr == _efl_net_connman_manager)
|
||||||
|
_efl_net_connman_manager = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Eina_Bool
|
||||||
|
efl_net_connman_init(void)
|
||||||
|
{
|
||||||
|
Eldbus_Object *obj;
|
||||||
|
|
||||||
|
_efl_net_connman_init_count++;
|
||||||
|
if (_efl_net_connman_init_count > 1) return EINA_TRUE;
|
||||||
|
|
||||||
|
if (!eldbus_init())
|
||||||
|
{
|
||||||
|
ERR("could not init eldbus");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
_efl_net_connman_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
|
||||||
|
if (!_efl_net_connman_conn)
|
||||||
|
{
|
||||||
|
ERR("could not get DBus system connection");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("DBus unique name %s", eldbus_connection_unique_name_get(_efl_net_connman_conn));
|
||||||
|
|
||||||
|
obj = eldbus_object_get(_efl_net_connman_conn, "net.connman", "/");
|
||||||
|
if (!obj)
|
||||||
|
{
|
||||||
|
ERR("could not create DBus object for name='net.connman', path='/'");
|
||||||
|
goto error_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
_efl_net_connman_manager = eldbus_proxy_get(obj, "net.connman.Manager");
|
||||||
|
if (!_efl_net_connman_manager)
|
||||||
|
{
|
||||||
|
ERR("could not create DBus proxy for interface='net.connman.Manager', name='net.connman', path='/'");
|
||||||
|
goto error_proxy;
|
||||||
|
}
|
||||||
|
eldbus_proxy_free_cb_add(_efl_net_connman_manager, _efl_net_connman_manager_free, NULL);
|
||||||
|
|
||||||
|
DBG("ConnMan support initialized");
|
||||||
|
return EINA_TRUE;
|
||||||
|
|
||||||
|
error_proxy:
|
||||||
|
eldbus_object_unref(obj);
|
||||||
|
|
||||||
|
error_obj:
|
||||||
|
eldbus_connection_unref(_efl_net_connman_conn);
|
||||||
|
_efl_net_connman_conn = NULL;
|
||||||
|
|
||||||
|
error:
|
||||||
|
_efl_net_connman_init_count = 0;
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
efl_net_connman_shutdown(void)
|
||||||
|
{
|
||||||
|
_efl_net_connman_init_count--;
|
||||||
|
if (_efl_net_connman_init_count > 0) return;
|
||||||
|
|
||||||
|
DBG("ConnMan support shutting down");
|
||||||
|
|
||||||
|
if (_efl_net_connman_manager)
|
||||||
|
{
|
||||||
|
Eldbus_Object *obj = eldbus_proxy_object_get(_efl_net_connman_manager);
|
||||||
|
eldbus_proxy_unref(_efl_net_connman_manager);
|
||||||
|
_efl_net_connman_manager = NULL;
|
||||||
|
eldbus_object_unref(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_efl_net_connman_conn)
|
||||||
|
{
|
||||||
|
eldbus_connection_unref(_efl_net_connman_conn);
|
||||||
|
_efl_net_connman_conn = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
eldbus_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
Eldbus_Connection *
|
||||||
|
efl_net_connman_connection_get(void)
|
||||||
|
{
|
||||||
|
return _efl_net_connman_conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
Eldbus_Proxy *
|
||||||
|
efl_net_connman_manager_get(void)
|
||||||
|
{
|
||||||
|
return _efl_net_connman_manager;
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
#ifndef _EFL_NET_CONNMAN_H_
|
||||||
|
#define _EFL_NET_CONNMAN_H_ 1
|
||||||
|
|
||||||
|
#include "Ecore.h"
|
||||||
|
#include "ecore_con_private.h"
|
||||||
|
|
||||||
|
#include "Eldbus.h"
|
||||||
|
|
||||||
|
#define DEFAULT_TIMEOUT 10000.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file efl_net-connman.h
|
||||||
|
*
|
||||||
|
* Common infrastructure to create Efl_Net_Control and Efl_Net_Session
|
||||||
|
* based on ConnMan connection manager.
|
||||||
|
*
|
||||||
|
* @note Each connection manager that needs shared infra should create
|
||||||
|
* their own file!
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be called from inside Efl.Object.constructor before using
|
||||||
|
* any of connman functions.
|
||||||
|
*
|
||||||
|
* @return #EINA_FALSE on errors, all other functions will be useless
|
||||||
|
* in this case. #EINA_TRUE on success.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
Eina_Bool efl_net_connman_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be called from inside Efl.Object.destructor after done using
|
||||||
|
* all of connman functions.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
void efl_net_connman_shutdown(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the DBus connection shared by all objects.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
Eldbus_Connection *efl_net_connman_connection_get(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a singleton for ConnMan's Manager object and interface
|
||||||
|
* (proxy).
|
||||||
|
*
|
||||||
|
* @note call efl_net_connman_init() before using. There is no need to
|
||||||
|
* eldbus_proxy_ref() it, but if done should have a matching
|
||||||
|
* eldbus_proxy_unref(). After done, remember to
|
||||||
|
* efl_net_connman_shutdown().
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
Eldbus_Proxy *efl_net_connman_manager_get(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a Efl.Net.Control find a technology instance given its name.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
Efl_Net_Control_Technology *efl_net_connman_control_find_technology_by_type(Efl_Net_Control *ctl, const char *tech_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask Efl.Net.Control to reload access point list.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
void efl_net_connman_control_access_points_reload(Efl_Net_Control *ctl);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Efl.Net.Control.Technology child of an
|
||||||
|
* Efl.Net.Control with path and properties
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
Efl_Net_Control_Technology *efl_net_connman_technology_new(Efl_Net_Control *parent, const char *path, Eldbus_Message_Iter *properties);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path of the given technology.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
const char *efl_net_connman_technology_path_get(Efl_Net_Control_Technology *tech);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert connman's type string to enum value.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
Efl_Net_Control_Technology_Type efl_net_connman_technology_type_from_str(const char *tech_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Efl.Net.Control.Access_Point child of an
|
||||||
|
* Efl.Net.Control with path and properties
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
Efl_Net_Control_Access_Point *efl_net_connman_access_point_new(Efl_Net_Control *parent, const char *path, Eldbus_Message_Iter *properties, unsigned int priority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path of the given access_point.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
const char *efl_net_connman_access_point_path_get(Efl_Net_Control_Access_Point *ap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates Efl.Net.Control.Access_Point properties
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
void efl_net_connman_access_point_update(Efl_Net_Control *ap, Eldbus_Message_Iter *properties, unsigned int priority);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _EFL_NET_CONNMAN_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,213 @@
|
||||||
|
import eina_types;
|
||||||
|
import efl_net_control_access_point;
|
||||||
|
import efl_net_control_technology;
|
||||||
|
|
||||||
|
enum Efl.Net.Control.State {
|
||||||
|
[[Provides the global network connectivity state.
|
||||||
|
|
||||||
|
For fine grained details, use @Efl.Net.Control access points and
|
||||||
|
their state property.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
offline, [[no access point is connected]]
|
||||||
|
local, [[at least one access point was connected and the internet connectio wasn't verified]]
|
||||||
|
online, [[at least one access point was connected and the internet was verified]]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Efl.Net.Control.Agent_Request_Input.Field {
|
||||||
|
[[Bitwise-able fields requested to the agent.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
name = (1 << 0), [[Used for hidden WiFi access points. If ssid is present, this is an alternative to that.]]
|
||||||
|
ssid = (1 << 1), [[Used for hidden WiFi access points. If name is present, this is an alternative to that.]]
|
||||||
|
username = (1 << 2), [[Identity or username requested]]
|
||||||
|
passphrase = (1 << 3), [[password or passphrase requested]]
|
||||||
|
wps = (1 << 4), [[Use WPS authentication. If passphrase is present, this is an alternative to that.]]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Efl.Net.Control.Agent_Request_Input.Information {
|
||||||
|
[[Name-value information pair provided to the agent.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
name: string; [[The information name, such as PreviousPassphrase, Host, Name...]]
|
||||||
|
value: string; [[The contents of the information]]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Efl.Net.Control.Agent_Request_Input {
|
||||||
|
[[Request input to the agent.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
access_point: Efl.Net.Control.Access_Point; [[The access point that triggered this request.]]
|
||||||
|
fields: Efl.Net.Control.Agent_Request_Input.Field; [[Bitwise OR of fields present in this request.]]
|
||||||
|
passphrase_type: string; [[Extra detail on the meaning for the passphrase field, such as wep, psk, response (IEEE802.X GTC/OTP), string...]]
|
||||||
|
informational: list<Efl.Net.Control.Agent_Request_Input.Information>; [[such as the previous passphrase, VPN host]]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Efl.Net.Control.Agent_Error {
|
||||||
|
[[Report error to the agent.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
access_point: Efl.Net.Control.Access_Point; [[The access point that triggered this error.]]
|
||||||
|
message: string; [[The error message.]]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Efl.Net.Control.Agent_Browser_Url {
|
||||||
|
[[Report to agent that it should open a browser at given URL.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
access_point: Efl.Net.Control.Access_Point; [[The access point that triggered this request.]]
|
||||||
|
url: string; [[The URL to point the browser at.]]
|
||||||
|
}
|
||||||
|
|
||||||
|
class Efl.Net.Control (Efl.Loop_User) {
|
||||||
|
[[Control network connectivity.
|
||||||
|
|
||||||
|
This class and its children objects are only useful to implement
|
||||||
|
control of the network connectivity. If your application is only
|
||||||
|
interested in requesting access to the network, use the
|
||||||
|
\@Efl.Net.Session instead.
|
||||||
|
|
||||||
|
The network connectivity is defined on top of technologies that
|
||||||
|
provide access points. A technology can be "ethernet", "wifi",
|
||||||
|
"bluetooth" or something else. Ethernet will provide a single
|
||||||
|
access point, while "wifi" will expose zero or more access
|
||||||
|
points that can come and go.
|
||||||
|
|
||||||
|
Users willing to use access points are expected to monitor
|
||||||
|
"access_point,add" event to know when access points were
|
||||||
|
added. To know when they were deleted, "access_point,del" or an
|
||||||
|
@Efl.Net.Control.Access_Point "del" event. Finally
|
||||||
|
"access_points,changed" is relative to additions, deletions and
|
||||||
|
reordering of access point due changes in their priorities.
|
||||||
|
|
||||||
|
The backend system is responsible to remember connection details
|
||||||
|
such as passphrase, last connected access point and
|
||||||
|
priority. The user is NOT supposed to do that.
|
||||||
|
|
||||||
|
For ease of use, @.state tells if at least one access point is
|
||||||
|
online (verified connectivity), local (connected but unverified)
|
||||||
|
or offline.
|
||||||
|
|
||||||
|
Due safety reasons all radio transmissions may be disabled with
|
||||||
|
@.radios_offline property. This is usually called "airplane
|
||||||
|
mode" in some platforms.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
events {
|
||||||
|
access_point,add: Efl.Net.Control.Access_Point; [[The given access point was added]]
|
||||||
|
access_point,del: Efl.Net.Control.Access_Point; [[The given access point will be deleted]]
|
||||||
|
access_points,changed; [[Access points were added, deleted or reordered.]]
|
||||||
|
technology,add: Efl.Net.Control.Technology; [[The given technology was added]]
|
||||||
|
technology,del: Efl.Net.Control.Technology; [[The given technology will be deleted]]
|
||||||
|
radios_offline,changed; [[Property @.radios_offline changed]]
|
||||||
|
state,changed; [[Property @.state changed]]
|
||||||
|
|
||||||
|
agent_released; [[Notifies we're not the agent anymore]]
|
||||||
|
agent_error: Efl.Net.Control.Agent_Error; [[Requires the error to be reported to the user]]
|
||||||
|
agent_browser_url: Efl.Net.Control.Agent_Browser_Url; [[Requires the user to visit a web page]]
|
||||||
|
agent_request_input: Efl.Net.Control.Agent_Request_Input; [[Requires the user to enter information in order to proceed, such as hidden SSID, passphrase, etc. After the user entered information, reply by calling @.agent_reply]]
|
||||||
|
}
|
||||||
|
|
||||||
|
methods {
|
||||||
|
@property radios_offline {
|
||||||
|
[[If $true disable all network technologies that use radio transmission, such as bluetooth and wifi. If $false, allows radios to be used.]]
|
||||||
|
get { }
|
||||||
|
set { }
|
||||||
|
values {
|
||||||
|
radios_offline: bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property state {
|
||||||
|
[[Summary of network connectivity.
|
||||||
|
|
||||||
|
- offline means no connectivity;
|
||||||
|
|
||||||
|
- local means local connectivity, that is, the access
|
||||||
|
point is connected but couldn't reach the internet;
|
||||||
|
|
||||||
|
- online means verified connectivity.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
state: Efl.Net.Control.State;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property access_points {
|
||||||
|
[[The iterator of current access points.
|
||||||
|
|
||||||
|
The iterator is valid only before the function returns
|
||||||
|
to the main loop, by then, if the events
|
||||||
|
"access_point,add" or "access_point,del" are emitted,
|
||||||
|
the iterator will become invalid.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
access_points: free(own(iterator<Efl.Net.Control.Access_Point>), eina_iterator_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property technologies {
|
||||||
|
[[The iterator of current access points.
|
||||||
|
|
||||||
|
The iterator is valid only before the function returns
|
||||||
|
to the main loop, by then, if the events
|
||||||
|
"technology,add" or "technology,del" are emitted,
|
||||||
|
the iterator will become invalid.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
technologies: free(own(iterator<Efl.Net.Control.Technology>), eina_iterator_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property agent_enabled {
|
||||||
|
[[The agent is responsible for user interaction.
|
||||||
|
|
||||||
|
When enabled, the local process will become the agent
|
||||||
|
for user interaction, such as requesting passphrases,
|
||||||
|
asking the user to open a browser to do
|
||||||
|
web-authentication and report connection errors.
|
||||||
|
|
||||||
|
There can be a single agent in the system at a given
|
||||||
|
time, registering one will unregister the other and
|
||||||
|
special permissions may be required to become an agent.
|
||||||
|
|
||||||
|
An useful agent should monitor "agent_error",
|
||||||
|
"agent_browser_url" and "agent_request_input"
|
||||||
|
events. When input is requested, reply using
|
||||||
|
@.agent_reply.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
set { }
|
||||||
|
values {
|
||||||
|
agent_enabled: bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
agent_reply {
|
||||||
|
[[If event "agent_request_input" was emitted, this will reply with the requested data]]
|
||||||
|
params {
|
||||||
|
name: string @nullable; [[If @Efl.Net.Control.Agent_Request_Input.Field.name was present, this should contain the network name or the 'ssid' parameter should be used.]]
|
||||||
|
ssid: const(Eina.Slice)* @nullable; [[If @Efl.Net.Control.Agent_Request_Input.Field.ssid was present, this should contain the network SSID or the 'name' parameter should be used.]]
|
||||||
|
username: string @nullable; [[If @Efl.Net.Control.Agent_Request_Input.Field.username was present, this should contain the identity or username]]
|
||||||
|
passphrase: string @nullable; [[If @Efl.Net.Control.Agent_Request_Input.Field.passphrase was present, this should contain the password or passphrase, more details on how it should be interpreted was given in Efl.Net.Control.Agent_Request_Input.passphrase_type.]]
|
||||||
|
wps: string @nullable; [[If @Efl.Net.Control.Agent_Request_Input.Field.wps was present, this should contain the WPS PIN or an empty string "" to use the WPS push button instead.]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implements {
|
||||||
|
Efl.Object.destructor;
|
||||||
|
Efl.Object.constructor;
|
||||||
|
Efl.Object.finalize;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,463 @@
|
||||||
|
enum Efl.Net.Control.Access_Point.State {
|
||||||
|
[[Provides the access point state.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
idle, [[nothing is happening with this access point]]
|
||||||
|
association, [[the access point is trying to associate itself, this is the first state after a connection attempt]]
|
||||||
|
configuration, [[the access point is configuring itself, such as DHCP]]
|
||||||
|
local, [[the access point is connected, but the internet connection wasn't validated]]
|
||||||
|
online, [[the access point is connected and the internet connected was validated]]
|
||||||
|
disconnect, [[the access point is disconnecting]]
|
||||||
|
failure, [[a connection attempt failed, @Efl.Net.Control.Access_Point.error will provide more details]]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Efl.Net.Control.Access_Point.Error {
|
||||||
|
[[The connection error reason.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
none, [[all right, no errors]]
|
||||||
|
out_of_range, [[wireless device is out of range]]
|
||||||
|
pin_missing, [[PIN was required and is missing]]
|
||||||
|
dhcp_failed, [[DHCP failed to provide configuration]]
|
||||||
|
connect_failed, [[couldn't connect to access point]]
|
||||||
|
login_failed, [[login or authentication information was incorrect, agent_request_input event may be emitted]]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Efl.Net.Control.Access_Point.Security {
|
||||||
|
[[Bitwise-able securities supported by an access point.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
unknow = 0,
|
||||||
|
none = (1 << 0), [[open access, no security]]
|
||||||
|
wep = (1 << 1), [[WEP]]
|
||||||
|
psk = (1 << 2), [[PSK (Pre Shared Key), such as WPA or RSN]]
|
||||||
|
ieee802_1x = (1 << 3), [[IEEE 802.1X]]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Efl.Net.Control.Access_Point.Ipv4_Method {
|
||||||
|
[[The method used to configure IPv4
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
off, [[IPv4 is disabled]]
|
||||||
|
dhcp, [[IPv4 is configured using DHCP]]
|
||||||
|
manual, [[IPv4 is manually set using address, netmask and gateway]]
|
||||||
|
unset, [[Only to be used with @Efl.Net.Control.Access_Point.configuration_ipv4]]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Efl.Net.Control.Access_Point.Ipv6_Method {
|
||||||
|
[[The method used to configure IPv6
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
off, [[IPv6 is disabled]]
|
||||||
|
fixed, [[IPv6 is fixed by operator and cannot be changed]]
|
||||||
|
manual, [[IPv6 is manually set using address, netmask and gateway]]
|
||||||
|
auto_privacy_none, [[IPv6 is set using dhcp or using a tunnel6to4, no privacy extensions should be used]]
|
||||||
|
auto_privacy_public, [[IPv6 is set using dhcp or using a tunnel6to4, privacy extensions are used and the system prefers a public IP address over temporary addresses]]
|
||||||
|
auto_privacy_temporary, [[IPv6 is set using dhcp or using a tunnel6to4, privacy extensions are used and the system prefers a temporary IP address over public addresses]]
|
||||||
|
tunnel6to4, [[IPv6 was configured using a 6-to-4 tunnel. This cannot be set by the user, which is expected to set "auto" instead]]
|
||||||
|
unset, [[Only to be used with @Efl.Net.Control.Access_Point.configuration_ipv6]]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Efl.Net.Control.Access_Point.Proxy_Method {
|
||||||
|
[[The method used to configure Proxy.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
off, [[direct connection to the internet, no proxy to be used]]
|
||||||
|
auto, [[proxy is autoconfigured using Proxy-Auto-Configuration (PAC) using given URL]]
|
||||||
|
manual, [[proxy is configured manually using servers and excludes]]
|
||||||
|
unset, [[Only to be used with @Efl.Net.Control.Access_Point.configuration_proxy]]
|
||||||
|
}
|
||||||
|
|
||||||
|
class Efl.Net.Control.Access_Point (Efl.Loop_User) {
|
||||||
|
[[An access point for network connectivity.
|
||||||
|
|
||||||
|
The @Efl.Net.Control is composed of multiple technologies, each
|
||||||
|
create access points to allow configuration and connection.
|
||||||
|
|
||||||
|
An application willing to just get a network connection should
|
||||||
|
prefer to use the \@Efl.Net.Session instead.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
|
||||||
|
events {
|
||||||
|
changed; [[Some properties were changed.]]
|
||||||
|
}
|
||||||
|
|
||||||
|
methods {
|
||||||
|
connect {
|
||||||
|
[[Connect to this access point.
|
||||||
|
|
||||||
|
This connection will happen asynchronously in the
|
||||||
|
background, with results being delivered by events in
|
||||||
|
the access point object, such as the "changed".
|
||||||
|
|
||||||
|
Successful connections will remember the device and set
|
||||||
|
it to auto-connect using the property @.auto_connect.
|
||||||
|
|
||||||
|
See @.forget, @.remembered, @.auto_connect and
|
||||||
|
@.disconnect
|
||||||
|
|
||||||
|
The future may fail with non-fatal errors such as
|
||||||
|
EINPROGRESS (the connection was already ongoing) and
|
||||||
|
EALREADY (the connection was already stablished).
|
||||||
|
]]
|
||||||
|
return: future<void_ptr>; /* NOTE: This should be future<void> */
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect {
|
||||||
|
[[Disconnect from this access point.
|
||||||
|
|
||||||
|
When disconnected a previously connected access point it
|
||||||
|
won't be forgotten. The configuration and other details
|
||||||
|
such as priority and passphrase will be available for a
|
||||||
|
future re-connection with call to @.connect. If it is
|
||||||
|
desired to disconnect and forget all access point
|
||||||
|
information, use @.forget instead.
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
forget {
|
||||||
|
[[Disconnect and forget about this access point.
|
||||||
|
|
||||||
|
Successful @.connect will always remember the access
|
||||||
|
point for future re-connections. This method reverts
|
||||||
|
that by disconnecting and forgetting about the access
|
||||||
|
point and its configuration, which will set the
|
||||||
|
@.remembered to $false.
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@property state {
|
||||||
|
[[The current state of this access point.
|
||||||
|
|
||||||
|
Whenever the state changes, "changed" will be emitted.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
state: Efl.Net.Control.Access_Point.State;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property error {
|
||||||
|
[[If the access point is in error state, this states the error.]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
error: Efl.Net.Control.Access_Point.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property name {
|
||||||
|
[[The user-friendly access point name.
|
||||||
|
|
||||||
|
For hidden WiFi networks, this is empty.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property priority {
|
||||||
|
[[The access point priority in the current access point listing.
|
||||||
|
|
||||||
|
This property is dynamic and reflects the index of the
|
||||||
|
access point in the current access points list. As
|
||||||
|
access points may come and go, the value may change at
|
||||||
|
any time and notified with "changed" event.
|
||||||
|
|
||||||
|
If set, then it will reoder priorities, moving all other
|
||||||
|
services at equal or higher priority up. To move as the
|
||||||
|
first (most priority), then use 0. To move as the last
|
||||||
|
priority, use UINT32_MAX or the last known priority + 1.
|
||||||
|
|
||||||
|
\@note Only remembered access points may be reordered
|
||||||
|
among themselves. Those that are not remembered will
|
||||||
|
always come last in random order defined by the backend.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
set { }
|
||||||
|
values {
|
||||||
|
priority: uint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property technology {
|
||||||
|
[[The technology that generated this access point]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
technology: Efl.Net.Control.Technology;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property strength {
|
||||||
|
[[Signal strength percentage in 0-100]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
strength: uint8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property roaming {
|
||||||
|
[[If it's a cellular access point and it's on roaming.]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
roaming: bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property auto_connect {
|
||||||
|
[[Whenever to auto-connect to this access point if no other is connected.
|
||||||
|
|
||||||
|
By default successfully connected access points are
|
||||||
|
remembered and set to auto-connect. This behavior can be
|
||||||
|
changed with this property.
|
||||||
|
|
||||||
|
An access point is only connected automatically if there
|
||||||
|
are no other connected and if it is not on roaming.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
set { }
|
||||||
|
values {
|
||||||
|
auto_connect: bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property remembered {
|
||||||
|
[[Successfully connected access points are remembered.
|
||||||
|
|
||||||
|
To forget about this access point, call @.forget.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
remembered: bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property immutable {
|
||||||
|
[[Immutable access points are those defined in configuration files and its properties can't be changed using API.]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
immutable: bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property security {
|
||||||
|
[[Security options such as wep, wps, psk or none (open).]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
security: Efl.Net.Control.Access_Point.Security; [[Bitwise OR of security supported by this access point]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property name_servers {
|
||||||
|
[[DNS (Domain Name Servers) in use for this access point.
|
||||||
|
|
||||||
|
These are the actual values in use, configure them using
|
||||||
|
@.configuration_name_servers, which may generate change
|
||||||
|
to this property, being notified with the "changed"
|
||||||
|
event.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
name_servers: free(own(iterator<string>), eina_iterator_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property time_servers {
|
||||||
|
[[NTP (Time Server) in use for this access point.
|
||||||
|
|
||||||
|
These are the actual values in use, configure them using
|
||||||
|
@.configuration_time_servers, which may generate change
|
||||||
|
to this property, being notified with the "changed"
|
||||||
|
event.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
time_servers: free(own(iterator<string>), eina_iterator_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property domains {
|
||||||
|
[[Search domains in use for this access point.
|
||||||
|
|
||||||
|
These are the actual values in use, configure them using
|
||||||
|
@.configuration_domains, which may generate change
|
||||||
|
to this property, being notified with the "changed"
|
||||||
|
event.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
domains: free(own(iterator<string>), eina_iterator_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property ipv4 {
|
||||||
|
[[IPv4 in use for this access point.
|
||||||
|
|
||||||
|
These are the actual values in use, configure them using
|
||||||
|
@.configuration_ipv4, which may generate change
|
||||||
|
to this property, being notified with the "changed"
|
||||||
|
event.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
method: Efl.Net.Control.Access_Point.Ipv4_Method;
|
||||||
|
address: string;
|
||||||
|
netmask: string;
|
||||||
|
gateway: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property ipv6 {
|
||||||
|
[[IPv6 in use for this access point.
|
||||||
|
|
||||||
|
These are the actual values in use, configure them using
|
||||||
|
@.configuration_ipv6, which may generate change
|
||||||
|
to this property, being notified with the "changed"
|
||||||
|
event.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
method: Efl.Net.Control.Access_Point.Ipv6_Method;
|
||||||
|
address: string;
|
||||||
|
prefix_length: uint8;
|
||||||
|
netmask: string;
|
||||||
|
gateway: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property proxy {
|
||||||
|
[[Proxy in use for this access point.
|
||||||
|
|
||||||
|
These are the actual values in use, configure them using
|
||||||
|
@.configuration_proxy, which may generate change
|
||||||
|
to this property, being notified with the "changed"
|
||||||
|
event.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
method: Efl.Net.Control.Access_Point.Proxy_Method;
|
||||||
|
url: string; [[if @Efl.Net.Control.Access_Point.Proxy_Method.auto, then states the URL to use for proxy auto-configuration]]
|
||||||
|
servers: free(own(iterator<string>), eina_iterator_free); [[If @Efl.Net.Control.Access_Point.Proxy_Method.manual, then states the URI with proxy servers to use, like "http://proxy.domain.com:911"]]
|
||||||
|
excludes: free(own(iterator<string>), eina_iterator_free); [[If @Efl.Net.Control.Access_Point.Proxy_Method.manual, then states the hosts or patterns to exclude from proxy access, such as "localhost", ".domain.com", or "10.0.0.0..."]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property configuration_name_servers {
|
||||||
|
[[DNS (Domain Name Servers) configured by user for this access point.
|
||||||
|
|
||||||
|
These are the user configured values, that will be
|
||||||
|
applied by the backend system and in turn may result in
|
||||||
|
"changed" event to notify of @.name_servers property
|
||||||
|
with the actual value in use, which may differ from
|
||||||
|
this.
|
||||||
|
]]
|
||||||
|
set { }
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
name_servers: free(own(iterator<string>), eina_iterator_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property configuration_time_servers {
|
||||||
|
[[NTP (Time Server) configured by user for this access point.
|
||||||
|
|
||||||
|
These are the user configured values, that will be
|
||||||
|
applied by the backend system and in turn may result in
|
||||||
|
"changed" event to notify of @.time_servers property
|
||||||
|
with the actual value in use, which may differ from
|
||||||
|
this.
|
||||||
|
]]
|
||||||
|
set { }
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
time_servers: free(own(iterator<string>), eina_iterator_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property configuration_domains {
|
||||||
|
[[Search domains configured by user for this access point.
|
||||||
|
|
||||||
|
These are the user configured values, that will be
|
||||||
|
applied by the backend system and in turn may result in
|
||||||
|
"changed" event to notify of @.domains property
|
||||||
|
with the actual value in use, which may differ from
|
||||||
|
this.
|
||||||
|
]]
|
||||||
|
set { }
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
domains: free(own(iterator<string>), eina_iterator_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property configuration_ipv4 {
|
||||||
|
[[IPv4 configured by user for this access point.
|
||||||
|
|
||||||
|
These are the user configured values, that will be
|
||||||
|
applied by the backend system and in turn may result in
|
||||||
|
"changed" event to notify of @.ipv4 property
|
||||||
|
with the actual value in use, which may differ from
|
||||||
|
this.
|
||||||
|
]]
|
||||||
|
set { }
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
method: Efl.Net.Control.Access_Point.Ipv4_Method;
|
||||||
|
address: string;
|
||||||
|
netmask: string;
|
||||||
|
gateway: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property configuration_ipv6 {
|
||||||
|
[[IPv6 configured by user for this access point.
|
||||||
|
|
||||||
|
These are the user configured values, that will be
|
||||||
|
applied by the backend system and in turn may result in
|
||||||
|
"changed" event to notify of @.ipv6 property
|
||||||
|
with the actual value in use, which may differ from
|
||||||
|
this.
|
||||||
|
]]
|
||||||
|
set { }
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
method: Efl.Net.Control.Access_Point.Ipv6_Method;
|
||||||
|
address: string;
|
||||||
|
prefix_length: uint8;
|
||||||
|
netmask: string;
|
||||||
|
gateway: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property configuration_proxy {
|
||||||
|
[[Proxy configured by user for this access point.
|
||||||
|
|
||||||
|
These are the user configured values, that will be
|
||||||
|
applied by the backend system and in turn may result in
|
||||||
|
"changed" event to notify of @.proxy property
|
||||||
|
with the actual value in use, which may differ from
|
||||||
|
this.
|
||||||
|
]]
|
||||||
|
set { }
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
method: Efl.Net.Control.Access_Point.Proxy_Method;
|
||||||
|
url: string; [[if @Efl.Net.Control.Access_Point.Proxy_Method.auto, then states the URL to use for proxy auto-configuration]]
|
||||||
|
servers: free(own(iterator<string>), eina_iterator_free); [[If @Efl.Net.Control.Access_Point.Proxy_Method.manual, then states the URI with proxy servers to use, like "http://proxy.domain.com:911"]]
|
||||||
|
excludes: free(own(iterator<string>), eina_iterator_free); [[If @Efl.Net.Control.Access_Point.Proxy_Method.manual, then states the hosts or patterns to exclude from proxy access, such as "localhost", ".domain.com", or "10.0.0.0..."]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implements {
|
||||||
|
Efl.Object.destructor;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,472 @@
|
||||||
|
#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/Eldbus_Object keeps a list of pending calls, but
|
||||||
|
* they are reference counted singletons and will only cancel
|
||||||
|
* pending calls when everything is gone. However we operate on
|
||||||
|
* our private data, that may be gone before other refs. So
|
||||||
|
* keep the pending list.
|
||||||
|
*/
|
||||||
|
Eina_List *pending;
|
||||||
|
Eina_List *signal_handlers;
|
||||||
|
Eldbus_Proxy *proxy;
|
||||||
|
Eina_Stringshare *path;
|
||||||
|
Eina_Stringshare *name;
|
||||||
|
struct {
|
||||||
|
Eina_Stringshare *identifier;
|
||||||
|
Eina_Stringshare *passphrase;
|
||||||
|
Eina_Bool enabled;
|
||||||
|
} tethering;
|
||||||
|
Efl_Net_Control_Technology_Type type;
|
||||||
|
Eina_Bool powered;
|
||||||
|
Eina_Bool connected;
|
||||||
|
} Efl_Net_Control_Technology_Data;
|
||||||
|
|
||||||
|
#define MY_CLASS EFL_NET_CONTROL_TECHNOLOGY_CLASS
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_powered_changed(Eo *o, Efl_Net_Control_Technology_Data *pd, Eldbus_Message_Iter *value)
|
||||||
|
{
|
||||||
|
Eina_Bool powered;
|
||||||
|
|
||||||
|
if (!eldbus_message_iter_arguments_get(value, "b", &powered))
|
||||||
|
{
|
||||||
|
ERR("Expected boolean, got %s", eldbus_message_iter_signature_get(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pd->powered == powered) return;
|
||||||
|
pd->powered = powered;
|
||||||
|
DBG("powered=%hhu", powered);
|
||||||
|
efl_event_callback_call(o, EFL_NET_CONTROL_TECHNOLOGY_EVENT_CHANGED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_connected_changed(Eo *o, Efl_Net_Control_Technology_Data *pd, Eldbus_Message_Iter *value)
|
||||||
|
{
|
||||||
|
Eina_Bool connected;
|
||||||
|
|
||||||
|
if (!eldbus_message_iter_arguments_get(value, "b", &connected))
|
||||||
|
{
|
||||||
|
ERR("Expected boolean, got %s", eldbus_message_iter_signature_get(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pd->connected == connected) return;
|
||||||
|
pd->connected = connected;
|
||||||
|
DBG("connected=%hhu", connected);
|
||||||
|
efl_event_callback_call(o, EFL_NET_CONTROL_TECHNOLOGY_EVENT_CHANGED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_name_changed(Eo *o, Efl_Net_Control_Technology_Data *pd, Eldbus_Message_Iter *value)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!eldbus_message_iter_arguments_get(value, "s", &name))
|
||||||
|
{
|
||||||
|
ERR("Expected string, got %s", eldbus_message_iter_signature_get(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eina_stringshare_replace(&pd->name, name)) return;
|
||||||
|
DBG("name=%s", name);
|
||||||
|
efl_event_callback_call(o, EFL_NET_CONTROL_TECHNOLOGY_EVENT_CHANGED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Efl_Net_Control_Technology_Type
|
||||||
|
efl_net_connman_technology_type_from_str(const char *str)
|
||||||
|
{
|
||||||
|
const struct {
|
||||||
|
Efl_Net_Control_Technology_Type val;
|
||||||
|
const char *str;
|
||||||
|
} *itr, map[] = {
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_UNKNOWN, "unknown"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_SYSTEM, "system"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_ETHERNET, "ethernet"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_WIFI, "wifi"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_BLUETOOTH, "bluetooth"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_CELLULAR, "cellular"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_GPS, "gps"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_VPN, "vpn"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_GADGET, "gadget"},
|
||||||
|
{EFL_NET_CONTROL_TECHNOLOGY_TYPE_P2P, "p2p"},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (itr = map; itr->str != NULL; itr++)
|
||||||
|
if (strcmp(itr->str, str) == 0) return itr->val;
|
||||||
|
|
||||||
|
ERR("Unknown type '%s'", str);
|
||||||
|
return EFL_NET_CONTROL_TECHNOLOGY_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_type_changed(Eo *o, Efl_Net_Control_Technology_Data *pd, Eldbus_Message_Iter *value)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
Efl_Net_Control_Technology_Type type;
|
||||||
|
|
||||||
|
if (!eldbus_message_iter_arguments_get(value, "s", &str))
|
||||||
|
{
|
||||||
|
ERR("Expected string, got %s", eldbus_message_iter_signature_get(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = efl_net_connman_technology_type_from_str(str);
|
||||||
|
if (pd->type == type) return;
|
||||||
|
pd->type = type;
|
||||||
|
DBG("type=%d (%s)", type, str);
|
||||||
|
efl_event_callback_call(o, EFL_NET_CONTROL_TECHNOLOGY_EVENT_CHANGED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_tethering_changed(Eo *o, Efl_Net_Control_Technology_Data *pd, Eldbus_Message_Iter *value)
|
||||||
|
{
|
||||||
|
Eina_Bool tethering;
|
||||||
|
|
||||||
|
if (!eldbus_message_iter_arguments_get(value, "b", &tethering))
|
||||||
|
{
|
||||||
|
ERR("Expected boolean, got %s", eldbus_message_iter_signature_get(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pd->tethering.enabled == tethering) return;
|
||||||
|
pd->tethering.enabled = tethering;
|
||||||
|
DBG("tethering=%hhu", tethering);
|
||||||
|
efl_event_callback_call(o, EFL_NET_CONTROL_TECHNOLOGY_EVENT_CHANGED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_tethering_identifier_changed(Eo *o, Efl_Net_Control_Technology_Data *pd, Eldbus_Message_Iter *value)
|
||||||
|
{
|
||||||
|
const char *tethering_identifier;
|
||||||
|
|
||||||
|
if (!eldbus_message_iter_arguments_get(value, "s", &tethering_identifier))
|
||||||
|
{
|
||||||
|
ERR("Expected string, got %s", eldbus_message_iter_signature_get(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eina_stringshare_replace(&pd->tethering.identifier, tethering_identifier)) return;
|
||||||
|
DBG("tethering identifier=%s", tethering_identifier);
|
||||||
|
efl_event_callback_call(o, EFL_NET_CONTROL_TECHNOLOGY_EVENT_CHANGED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_tethering_passphrase_changed(Eo *o, Efl_Net_Control_Technology_Data *pd, Eldbus_Message_Iter *value)
|
||||||
|
{
|
||||||
|
const char *tethering_passphrase;
|
||||||
|
|
||||||
|
if (!eldbus_message_iter_arguments_get(value, "s", &tethering_passphrase))
|
||||||
|
{
|
||||||
|
ERR("Expected string, got %s", eldbus_message_iter_signature_get(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eina_stringshare_replace(&pd->tethering.passphrase, tethering_passphrase)) return;
|
||||||
|
DBG("tethering passphrase=%s", tethering_passphrase);
|
||||||
|
efl_event_callback_call(o, EFL_NET_CONTROL_TECHNOLOGY_EVENT_CHANGED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_changed_internal(Eo *o, Efl_Net_Control_Technology_Data *pd, Eldbus_Message_Iter *itr)
|
||||||
|
{
|
||||||
|
Eldbus_Message_Iter *value;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!eldbus_message_iter_arguments_get(itr, "sv", &name, &value))
|
||||||
|
{
|
||||||
|
ERR("Unexpected signature: %s", eldbus_message_iter_signature_get(itr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(name, "Powered") == 0)
|
||||||
|
_efl_net_control_technology_property_powered_changed(o, pd, value);
|
||||||
|
else if (strcmp(name, "Connected") == 0)
|
||||||
|
_efl_net_control_technology_property_connected_changed(o, pd, value);
|
||||||
|
else if (strcmp(name, "Name") == 0)
|
||||||
|
_efl_net_control_technology_property_name_changed(o, pd, value);
|
||||||
|
else if (strcmp(name, "Type") == 0)
|
||||||
|
_efl_net_control_technology_property_type_changed(o, pd, value);
|
||||||
|
else if (strcmp(name, "Tethering") == 0)
|
||||||
|
_efl_net_control_technology_property_tethering_changed(o, pd, value);
|
||||||
|
else if (strcmp(name, "TetheringIdentifier") == 0)
|
||||||
|
_efl_net_control_technology_property_tethering_identifier_changed(o, pd, value);
|
||||||
|
else if (strcmp(name, "TetheringPassphrase") == 0)
|
||||||
|
_efl_net_control_technology_property_tethering_passphrase_changed(o, pd, value);
|
||||||
|
else
|
||||||
|
WRN("Unknown property name: %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_changed(void *data, const Eldbus_Message *msg)
|
||||||
|
{
|
||||||
|
Eo *o = data;
|
||||||
|
Efl_Net_Control_Technology_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||||
|
Eldbus_Message_Iter *itr;
|
||||||
|
|
||||||
|
itr = eldbus_message_iter_get(msg);
|
||||||
|
_efl_net_control_technology_property_changed_internal(o, pd, itr);
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static void
|
||||||
|
_efl_net_control_technology_efl_object_destructor(Eo *o, Efl_Net_Control_Technology_Data *pd)
|
||||||
|
{
|
||||||
|
Eldbus_Pending *p;
|
||||||
|
Eldbus_Signal_Handler *sh;
|
||||||
|
|
||||||
|
EINA_LIST_FREE(pd->pending, p)
|
||||||
|
eldbus_pending_cancel(p);
|
||||||
|
|
||||||
|
EINA_LIST_FREE(pd->signal_handlers, sh)
|
||||||
|
eldbus_signal_handler_del(sh);
|
||||||
|
|
||||||
|
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_destructor(efl_super(o, MY_CLASS));
|
||||||
|
eina_stringshare_replace(&pd->path, NULL);
|
||||||
|
eina_stringshare_replace(&pd->name, NULL);
|
||||||
|
eina_stringshare_replace(&pd->tethering.identifier, NULL);
|
||||||
|
eina_stringshare_replace(&pd->tethering.passphrase, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_set_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
|
||||||
|
{
|
||||||
|
Eo *o = data;
|
||||||
|
Efl_Net_Control_Technology_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||||
|
const char *err_name, *err_msg;
|
||||||
|
|
||||||
|
pd->pending = eina_list_remove(pd->pending, pending);
|
||||||
|
if (eldbus_message_error_get(msg, &err_name, &err_msg))
|
||||||
|
{
|
||||||
|
ERR("Could not set property %p: %s=%s", o, err_name, err_msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_property_set(Eo *o, Efl_Net_Control_Technology_Data *pd, const char *name, const char *signature, ...)
|
||||||
|
{
|
||||||
|
Eldbus_Message *msg;
|
||||||
|
Eldbus_Message_Iter *msg_itr, *var;
|
||||||
|
Eldbus_Pending *p;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
msg = eldbus_proxy_method_call_new(pd->proxy, "SetProperty");
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(msg);
|
||||||
|
|
||||||
|
msg_itr = eldbus_message_iter_get(msg);
|
||||||
|
EINA_SAFETY_ON_NULL_GOTO(msg_itr, error_send);
|
||||||
|
|
||||||
|
eldbus_message_iter_basic_append(msg_itr, 's', name);
|
||||||
|
var = eldbus_message_iter_container_new(msg_itr, 'v', signature);
|
||||||
|
|
||||||
|
va_start(ap, signature);
|
||||||
|
eldbus_message_iter_arguments_vappend(var, signature, ap);
|
||||||
|
va_end(ap);
|
||||||
|
eldbus_message_iter_container_close(msg_itr, var);
|
||||||
|
|
||||||
|
p = eldbus_proxy_send(pd->proxy, msg, _efl_net_control_technology_property_set_cb, o, DEFAULT_TIMEOUT);
|
||||||
|
EINA_SAFETY_ON_NULL_GOTO(p, error_send);
|
||||||
|
|
||||||
|
pd->pending = eina_list_append(pd->pending, p);
|
||||||
|
DBG("Setting property %s", name);
|
||||||
|
return;
|
||||||
|
|
||||||
|
error_send:
|
||||||
|
eldbus_message_unref(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static void
|
||||||
|
_efl_net_control_technology_powered_set(Eo *o, Efl_Net_Control_Technology_Data *pd, Eina_Bool powered)
|
||||||
|
{
|
||||||
|
_efl_net_control_technology_property_set(o, pd, "Powered", "b", powered);
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static Eina_Bool
|
||||||
|
_efl_net_control_technology_powered_get(Eo *o EINA_UNUSED, Efl_Net_Control_Technology_Data *pd)
|
||||||
|
{
|
||||||
|
return pd->powered;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static void
|
||||||
|
_efl_net_control_technology_tethering_set(Eo *o, Efl_Net_Control_Technology_Data *pd, Eina_Bool enabled, const char *identifier, const char *passphrase)
|
||||||
|
{
|
||||||
|
if (passphrase)
|
||||||
|
_efl_net_control_technology_property_set(o, pd, "TetheringPassphrase", "s", passphrase);
|
||||||
|
|
||||||
|
if (identifier)
|
||||||
|
_efl_net_control_technology_property_set(o, pd, "TetheringIdentifier", "s", identifier);
|
||||||
|
|
||||||
|
_efl_net_control_technology_property_set(o, pd, "Tethering", "b", enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static void
|
||||||
|
_efl_net_control_technology_tethering_get(Eo *o EINA_UNUSED, Efl_Net_Control_Technology_Data *pd, Eina_Bool *enabled, const char **identifier, const char **passphrase)
|
||||||
|
{
|
||||||
|
if (enabled) *enabled = pd->tethering.enabled;
|
||||||
|
if (identifier) *identifier = pd->tethering.identifier;
|
||||||
|
if (passphrase) *passphrase = pd->tethering.passphrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static Eina_Bool
|
||||||
|
_efl_net_control_technology_connected_get(Eo *o EINA_UNUSED, Efl_Net_Control_Technology_Data *pd)
|
||||||
|
{
|
||||||
|
return pd->connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static const char *
|
||||||
|
_efl_net_control_technology_name_get(Eo *o EINA_UNUSED, Efl_Net_Control_Technology_Data *pd)
|
||||||
|
{
|
||||||
|
return pd->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static Efl_Net_Control_Technology_Type
|
||||||
|
_efl_net_control_technology_type_get(Eo *o EINA_UNUSED, Efl_Net_Control_Technology_Data *pd)
|
||||||
|
{
|
||||||
|
return pd->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_scan_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
|
||||||
|
{
|
||||||
|
Efl_Promise *promise = data;
|
||||||
|
Eo *o = efl_parent_get(promise);
|
||||||
|
Efl_Net_Control_Technology_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||||
|
const char *err_name, *err_msg;
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(pd);
|
||||||
|
|
||||||
|
pd->pending = eina_list_remove(pd->pending, pending);
|
||||||
|
efl_key_data_set(promise, "eldbus_pending", NULL);
|
||||||
|
if (eldbus_message_error_get(msg, &err_name, &err_msg))
|
||||||
|
{
|
||||||
|
Eina_Error err = EINVAL;
|
||||||
|
|
||||||
|
if (strcmp(err_name, "net.connman.Error.NotSupported") == 0)
|
||||||
|
err = ENOTSUP;
|
||||||
|
|
||||||
|
WRN("Could not Scan %p: %s=%s", o, err_name, err_msg);
|
||||||
|
efl_promise_failed_set(promise, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
efl_promise_value_set(promise, o, NULL);
|
||||||
|
efl_del(promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_efl_net_control_technology_scan_promise_del(void *data, const Efl_Event *event)
|
||||||
|
{
|
||||||
|
Eldbus_Pending *p;
|
||||||
|
Eo *o = data;
|
||||||
|
Efl_Net_Control_Technology_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(pd);
|
||||||
|
|
||||||
|
p = efl_key_data_get(event->object, "eldbus_pending");
|
||||||
|
if (!p) return; /* already gone, nothing to do */
|
||||||
|
|
||||||
|
pd->pending = eina_list_remove(pd->pending, p);
|
||||||
|
DBG("cancel pending scan %p", p);
|
||||||
|
eldbus_pending_cancel(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static Efl_Future *
|
||||||
|
_efl_net_control_technology_scan(Eo *o, Efl_Net_Control_Technology_Data *pd)
|
||||||
|
{
|
||||||
|
Eldbus_Pending *p;
|
||||||
|
Efl_Promise *promise;
|
||||||
|
|
||||||
|
promise = efl_add(EFL_PROMISE_CLASS, o,
|
||||||
|
efl_event_callback_add(efl_added, EFL_EVENT_DEL, _efl_net_control_technology_scan_promise_del, o));
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(promise, NULL);
|
||||||
|
|
||||||
|
p = eldbus_proxy_call(pd->proxy, "Scan",
|
||||||
|
_efl_net_control_technology_scan_cb, promise, -1.0, "");
|
||||||
|
EINA_SAFETY_ON_NULL_GOTO(p, error_dbus);
|
||||||
|
|
||||||
|
pd->pending = eina_list_append(pd->pending, p);
|
||||||
|
efl_key_data_set(promise, "eldbus_pending", p);
|
||||||
|
|
||||||
|
return efl_promise_future_get(promise);
|
||||||
|
|
||||||
|
error_dbus:
|
||||||
|
efl_promise_failed_set(promise, ENOSYS);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
efl_net_connman_technology_path_get(Efl_Net_Control_Technology *o)
|
||||||
|
{
|
||||||
|
Efl_Net_Control_Technology_Data *pd = efl_data_scope_get(o, MY_CLASS);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(pd, NULL);
|
||||||
|
return pd->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
Efl_Net_Control_Technology *
|
||||||
|
efl_net_connman_technology_new(Efl_Net_Control *ctl, const char *path, Eldbus_Message_Iter *itr)
|
||||||
|
{
|
||||||
|
Eo *o;
|
||||||
|
Efl_Net_Control_Technology_Data *pd;
|
||||||
|
Eldbus_Message_Iter *entry;
|
||||||
|
Eldbus_Connection *conn;
|
||||||
|
Eldbus_Object *obj;
|
||||||
|
|
||||||
|
conn = efl_net_connman_connection_get();
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
|
||||||
|
|
||||||
|
o = efl_add(MY_CLASS, ctl);
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN_VAL(o, NULL);
|
||||||
|
|
||||||
|
pd = efl_data_scope_get(o, MY_CLASS);
|
||||||
|
EINA_SAFETY_ON_NULL_GOTO(pd, error);
|
||||||
|
|
||||||
|
pd->path = eina_stringshare_add(path);
|
||||||
|
EINA_SAFETY_ON_NULL_GOTO(pd->path, error);
|
||||||
|
|
||||||
|
obj = eldbus_object_get(conn, "net.connman", pd->path);
|
||||||
|
EINA_SAFETY_ON_NULL_GOTO(obj, error);
|
||||||
|
pd->proxy = eldbus_proxy_get(obj, "net.connman.Technology");
|
||||||
|
EINA_SAFETY_ON_NULL_GOTO(pd->proxy, error);
|
||||||
|
|
||||||
|
#define SH(sig, cb) \
|
||||||
|
do { \
|
||||||
|
Eldbus_Signal_Handler *sh = eldbus_proxy_signal_handler_add(pd->proxy, sig, cb, o); \
|
||||||
|
if (sh) pd->signal_handlers = eina_list_append(pd->signal_handlers, sh); \
|
||||||
|
else ERR("could not add DBus signal handler %s", sig); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
SH("PropertyChanged", _efl_net_control_technology_property_changed);
|
||||||
|
#undef SH
|
||||||
|
|
||||||
|
efl_event_freeze(o);
|
||||||
|
while (eldbus_message_iter_get_and_next(itr, 'e', &entry))
|
||||||
|
_efl_net_control_technology_property_changed_internal(o, pd, entry);
|
||||||
|
efl_event_thaw(o);
|
||||||
|
|
||||||
|
return o;
|
||||||
|
|
||||||
|
error:
|
||||||
|
efl_del(o);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "efl_net_control_technology.eo.c"
|
|
@ -0,0 +1,106 @@
|
||||||
|
enum Efl.Net.Control.Technology.Type {
|
||||||
|
[[Technology types
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
unknown,
|
||||||
|
system,
|
||||||
|
ethernet,
|
||||||
|
wifi,
|
||||||
|
bluetooth,
|
||||||
|
cellular,
|
||||||
|
gps,
|
||||||
|
vpn,
|
||||||
|
gadget,
|
||||||
|
p2p,
|
||||||
|
}
|
||||||
|
|
||||||
|
class Efl.Net.Control.Technology (Efl.Loop_User) {
|
||||||
|
[[A technology that enables network access points to be controlled.
|
||||||
|
|
||||||
|
The @Efl.Net.Control is composed of multiple technologies, each
|
||||||
|
can be disabled/enabled with @.powered property.
|
||||||
|
|
||||||
|
When powered, the technology will dynamically add and delete
|
||||||
|
access points to be available in
|
||||||
|
@Efl.Net.Control.access_points.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
events {
|
||||||
|
changed; [[Some properties were changed.]]
|
||||||
|
}
|
||||||
|
|
||||||
|
methods {
|
||||||
|
@property powered {
|
||||||
|
[[If $true the technology is available. If $false technology is disabled and if possible rfkill is used.]]
|
||||||
|
get { }
|
||||||
|
set { }
|
||||||
|
values {
|
||||||
|
powered: bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property tethering {
|
||||||
|
[[Tethering allows the default access point to be bridged to all clients connected through the technology.
|
||||||
|
|
||||||
|
A common case is to use the device as a router, such as
|
||||||
|
a phone doing tethering allows a laptop to connect to 4G
|
||||||
|
network.
|
||||||
|
]]
|
||||||
|
get { }
|
||||||
|
set { }
|
||||||
|
values {
|
||||||
|
enabled: bool; [[Whenever to enable or disable tethering for this technology]]
|
||||||
|
identifier: string @optional; [[The name to identify this tethering, in WiFi it will translate to SSID.]]
|
||||||
|
passphrase: string @optional; [[The passphrase for this tethering access, in WiFi it will translate to WPA passphrase.]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property connected {
|
||||||
|
[[If $true the technology has at least one access point connected.]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
connected: bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property name {
|
||||||
|
[[The user-friendly technology name]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property type {
|
||||||
|
[[The technology type, such as "ethernet" or "wifi"]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
type: Efl.Net.Control.Technology.Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scan {
|
||||||
|
[[Explicitly trigger a scan.
|
||||||
|
|
||||||
|
The scan will happen asynchronously in the background,
|
||||||
|
with the results being delivered by events in the
|
||||||
|
technology, @Efl.Net.Control or @Efl.Net.Control.Access_Point
|
||||||
|
associated with the technology. For example, scan on
|
||||||
|
WiFi will add and delete access points.
|
||||||
|
|
||||||
|
It is worth to mention that explicit scans should be
|
||||||
|
avoided. Rare cases are when user requested them, like
|
||||||
|
entering a configuration dialog which demands fresh
|
||||||
|
state. Otherwise prefer to let the system passively do
|
||||||
|
scans in a timely manner.
|
||||||
|
]]
|
||||||
|
return: future<void_ptr>; /* NOTE: This should be future<void> */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implements {
|
||||||
|
Efl.Object.destructor;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,792 @@
|
||||||
|
#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 void *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;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
DBG("configuration method %s", str);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "Address") == 0)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
DBG("address %s", str);
|
||||||
|
eina_stringshare_replace(&pd->ipv4.address, str);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "Gateway") == 0)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
DBG("gateway %s", str);
|
||||||
|
eina_stringshare_replace(&pd->ipv4.gateway, str);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "Netmask") == 0)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
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 void *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;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
DBG("configuration method %s", str);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "Address") == 0)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
DBG("address %s", str);
|
||||||
|
eina_stringshare_replace(&pd->ipv6.address, str);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "Gateway") == 0)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
DBG("gateway %s", str);
|
||||||
|
eina_stringshare_replace(&pd->ipv6.gateway, str);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "Netmask") == 0)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
DBG("netmask %s", str);
|
||||||
|
eina_stringshare_replace(&pd->ipv6.netmask, str);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "Netmask") == 0)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
DBG("netmask %s", str);
|
||||||
|
eina_stringshare_replace(&pd->ipv6.netmask, str);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "PrefixLength") == 0)
|
||||||
|
{
|
||||||
|
eldbus_message_iter_arguments_get(value, "y", &pd->ipv6.prefix_length);
|
||||||
|
DBG("prefix_length %hhu", pd->ipv6.prefix_length);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "Privacy") == 0)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
eldbus_message_iter_arguments_get(value, "s", &str);
|
||||||
|
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;
|
||||||
|
|
||||||
|
eldbus_message_iter_arguments_get(var, "as", &sub);
|
||||||
|
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 void *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",
|
||||||
|
.cb = _efl_net_session_notifier_release,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.member = "Update",
|
||||||
|
.in = ELDBUS_ARGS({"a{sv}", "settings"}),
|
||||||
|
.cb = _efl_net_session_notifier_update,
|
||||||
|
},
|
||||||
|
{ }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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_name_get(Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
|
||||||
|
{
|
||||||
|
return pd->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static Efl_Net_Session_State
|
||||||
|
_efl_net_session_state_get(Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
|
||||||
|
{
|
||||||
|
return pd->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static Efl_Net_Session_Technology
|
||||||
|
_efl_net_session_technology_get(Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
|
||||||
|
{
|
||||||
|
return pd->technology;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static const char *
|
||||||
|
_efl_net_session_interface_get(Eo *o EINA_UNUSED, Efl_Net_Session_Data *pd)
|
||||||
|
{
|
||||||
|
return pd->interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static void
|
||||||
|
_efl_net_session_ipv4_get(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(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"
|
|
@ -0,0 +1,137 @@
|
||||||
|
enum Efl.Net.Session.State {
|
||||||
|
[[Provides the session connectivity state.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
offline, [[no access point is connected]]
|
||||||
|
local, [[at least one access point was connected and the internet connectio wasn't verified]]
|
||||||
|
online, [[at least one access point was connected and the internet was verified]]
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep in sync with efl_net_control_technology.eo, comment what doesn't make sense */
|
||||||
|
enum Efl.Net.Session.Technology {
|
||||||
|
[[Bitwise-able technologies to allow for a network session.
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
unknown = 0,
|
||||||
|
/* system = (1 << 0), */
|
||||||
|
ethernet = (1 << 1),
|
||||||
|
wifi = (1 << 2),
|
||||||
|
bluetooth = (1 << 3),
|
||||||
|
cellular = (1 << 4),
|
||||||
|
/* gps = (1 << 5), */
|
||||||
|
vpn = (1 << 6),
|
||||||
|
gadget = (1 << 7),
|
||||||
|
/* p2p = (1 << 8), */
|
||||||
|
all = (Efl.Net.Session.Technology.ethernet | Efl.Net.Session.Technology.wifi | Efl.Net.Session.Technology.bluetooth | Efl.Net.Session.Technology.cellular | Efl.Net.Session.Technology.vpn | Efl.Net.Session.Technology.gadget),
|
||||||
|
}
|
||||||
|
|
||||||
|
class Efl.Net.Session (Efl.Loop_User) {
|
||||||
|
[[Used by application to request network connectivity.
|
||||||
|
|
||||||
|
This API is targeted at applications that need access to the
|
||||||
|
network, specifying the allowed bearer technologies to connect
|
||||||
|
to the internet, as well as if just local networking is enough
|
||||||
|
or validated internet access is required.
|
||||||
|
|
||||||
|
\@note the @.connect method is subject to backend policy. For
|
||||||
|
instance, ConnMan uses
|
||||||
|
https://github.com/aldebaran/connman/blob/master/doc/session-policy-format.txt
|
||||||
|
|
||||||
|
@since 1.19
|
||||||
|
]]
|
||||||
|
events {
|
||||||
|
changed; [[Some properties were changed.]]
|
||||||
|
}
|
||||||
|
|
||||||
|
methods {
|
||||||
|
connect {
|
||||||
|
[[Asks the session to be connected.
|
||||||
|
|
||||||
|
This method doesn't need to be called if all an
|
||||||
|
application want is to monitor the connectivity state,
|
||||||
|
like a poller that will only try to access the
|
||||||
|
webservice when there is an existing connection without
|
||||||
|
triggering one.
|
||||||
|
|
||||||
|
This method is subject to backend policy. For instance,
|
||||||
|
ConnMan uses
|
||||||
|
https://github.com/aldebaran/connman/blob/master/doc/session-policy-format.txt
|
||||||
|
]]
|
||||||
|
params {
|
||||||
|
online_required: bool; [[if $false, access points with local state are enough. If $true, the access point must be in online state, with a validated internet connection]]
|
||||||
|
technologies_allowed: Efl.Net.Session.Technology; [[Bitwise OR of technologies to allow]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect {
|
||||||
|
[[Indicates this session doesn't need a connection anymore.
|
||||||
|
|
||||||
|
This reverses the effect of @.connect, let the system
|
||||||
|
disconnect if nothing else needs a connection. One may
|
||||||
|
still use the session object to monitor the connectivity
|
||||||
|
state via properties and "changed" event.
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@property name {
|
||||||
|
[[The user-friendly access point name.]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property state {
|
||||||
|
[[If the session connectivity is offline, local or online.]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
state: Efl.Net.Session.State;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property technology {
|
||||||
|
[[The access point technology that backs this session]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
technology: Efl.Net.Session.Technology;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property interface {
|
||||||
|
[[The interface allows the application to assign the socket to a given device using SO_BINDTODEVICE]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
interface: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property ipv4 {
|
||||||
|
[[IPv4 in use for this session.]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
address: string;
|
||||||
|
netmask: string;
|
||||||
|
gateway: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@property ipv6 {
|
||||||
|
[[IPv6 in use for this session.]]
|
||||||
|
get { }
|
||||||
|
values {
|
||||||
|
address: string;
|
||||||
|
prefix_length: uint8;
|
||||||
|
netmask: string;
|
||||||
|
gateway: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implements {
|
||||||
|
Efl.Object.destructor;
|
||||||
|
Efl.Object.constructor;
|
||||||
|
Efl.Object.finalize;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue