From: Daniel Wagner <[email protected]>
During normal operation we only have to add or remove service
from service when the service enters or leaves READY or CONNECTED
state.
We need to do some more work (comparing) when a service or a
session is created. In the worst case we have n*m comparison
where n is the number of services and m the number of sessions.
The worst case happens if all session allow all kind of services
via the 'any' AllowedBearers. The most likely this is only relevant
for wifi.
The current implemention does not try to be extra clever, instead
it is kept as simple as possible. We can still optimize this later
if needed.
---
src/service.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 139 insertions(+)
diff --git a/src/service.c b/src/service.c
index ae4f9a9..dcd5571 100644
--- a/src/service.c
+++ b/src/service.c
@@ -127,6 +127,7 @@ struct connman_service {
bool hidden_service;
char *config_file;
char *config_entry;
+ GSList *sessions;
};
static bool allow_property_changed(struct connman_service *service);
@@ -1371,10 +1372,64 @@ static void default_changed(void)
__connman_notifier_default_changed(service);
}
+static bool is_session_connected(struct connman_session *session,
+ enum connman_service_state state)
+{
+ struct connman_session_config *config;
+
+ switch (state) {
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
+ case CONNMAN_SERVICE_STATE_IDLE:
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ break;
+ case CONNMAN_SERVICE_STATE_READY:
+ config = __connman_session_get_config(session);
+ if (config->type == CONNMAN_SESSION_TYPE_INTERNET)
+ return false;
+ case CONNMAN_SERVICE_STATE_ONLINE:
+ return true;
+ }
+
+ return false;
+}
+
+static void update_session_state(struct connman_service *service)
+{
+ GSList *list;
+
+ for (list = service->sessions; list; list = list->next) {
+ struct connman_session *session = list->data;
+ struct connman_service *assigned;
+ bool connected;
+
+ connected = is_session_connected(session, service->state);
+ assigned = __connman_session_get_service(session);
+
+ DBG("assigned %p connected %d", assigned, connected);
+
+ if (assigned == service) {
+ if (connected)
+ __connman_session_state_changed(session,
+ service);
+ else
+ __connman_session_remove_service(session,
+ service);
+ } else if (connected) {
+ if (!assigned)
+ __connman_session_add_service(session, service);
+ }
+ }
+}
+
static void state_changed(struct connman_service *service)
{
const char *str;
+ update_session_state(service);
+
__connman_notifier_service_state_changed(service, service->state);
str = state2string(service->state);
@@ -3415,9 +3470,76 @@ static bool is_ignore(struct connman_service *service)
return false;
}
+static bool match_session(struct connman_service *service,
+ struct connman_session *session)
+{
+ struct connman_session_config *config;
+ GSList *list;
+
+ config = __connman_session_get_config(session);
+
+ for (list = config->allowed_bearers; list; list = list->next) {
+ enum connman_service_type type = GPOINTER_TO_UINT(list->data);
+
+ if (type == service->type)
+ return true;
+ }
+
+ return false;
+}
+
+static void add_sessions(struct connman_service *service)
+{
+ GSList *list;
+
+ for (list = session_list; list; list = list->next) {
+ struct connman_session *session = list->data;
+
+ if (!match_session(service, session))
+ continue;
+
+ service->sessions = g_slist_prepend(service->sessions,
+ session);
+ }
+}
+
+static void remove_sessions(struct connman_service *service)
+{
+ GSList *list;
+
+ for (list = service->sessions; list; list = list->next) {
+ struct connman_session *session = list->data;
+
+ __connman_session_remove_service(session, service);
+ }
+
+ g_slist_free(service->sessions);
+}
+
+static void add_service_to_session(struct connman_service *service,
+ struct connman_session *session)
+{
+ service->sessions = g_slist_prepend(service->sessions, session);
+
+ if (!__connman_session_get_service(session) &&
+ is_session_connected(session, service->state))
+ __connman_session_add_service(session, service);
+}
+
+static void remove_service_from_session(struct connman_service *service,
+ struct connman_session *session)
+{
+ service->sessions = g_slist_remove(service->sessions, session);
+
+ if (__connman_session_get_service(session) == service)
+ __connman_session_remove_service(session, service);
+}
+
void __connman_service_set_active_session(struct connman_session *session,
bool enable, GSList *list)
{
+ GList *iter;
+
if (!list)
return;
@@ -3429,6 +3551,20 @@ void __connman_service_set_active_session(struct
connman_session *session,
while (list != NULL) {
enum connman_service_type type = GPOINTER_TO_INT(list->data);
+ for (iter = service_list; iter; iter = iter->next) {
+ struct connman_service *service = iter->data;
+
+ DBG("service %p %s", service, service->name);
+
+ if (service->type != type)
+ continue;
+
+ if (enable)
+ add_service_to_session(service, session);
+ else
+ remove_service_from_session(service, session);
+ }
+
switch (type) {
case CONNMAN_SERVICE_TYPE_ETHERNET:
case CONNMAN_SERVICE_TYPE_WIFI:
@@ -4341,6 +4477,7 @@ static void service_free(gpointer user_data)
reply_pending(service, ENOENT);
__connman_notifier_service_remove(service);
+ remove_sessions(service);
service_schedule_removed(service);
__connman_wispr_stop(service);
@@ -6655,6 +6792,7 @@ struct connman_service *
__connman_service_create_from_network(struct connman_ne
service->ipconfig_ipv6 = create_ip6config(service, index);
service_register(service);
+ add_sessions(service);
if (service->favorite) {
device = connman_network_get_device(service->network);
@@ -6810,6 +6948,7 @@ __connman_service_create_from_provider(struct
connman_provider *provider)
service->ipconfig_ipv6 = create_ip6config(service, index);
service_register(service);
+ add_sessions(service);
__connman_notifier_service_add(service, service->name);
service_schedule_added(service);
--
1.8.4.474.g128a96c
_______________________________________________
connman mailing list
[email protected]
https://lists.connman.net/mailman/listinfo/connman