int online_check_count;
};
-static void append_path(gpointer value, gpointer user_data)
-{
- struct connman_service *service = value;
- DBusMessageIter *iter = user_data;
-
- if (service->path == NULL)
- return;
-
- dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
- &service->path);
-}
-
-void __connman_service_list(DBusMessageIter *iter, void *user_data)
-{
- if (service_list == NULL)
- return;
-
- g_sequence_foreach(service_list, append_path, iter);
-}
-
struct find_data {
const char *path;
struct connman_service *service;
switch (service->type) {
case CONNMAN_SERVICE_TYPE_UNKNOWN:
case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_ETHERNET:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_GADGET:
service->favorite = g_key_file_get_boolean(keyfile,
service->identifier, "Favorite", NULL);
- autoconnect = g_key_file_get_boolean(keyfile,
- service->identifier, "AutoConnect", &error);
- if (error == NULL)
- service->autoconnect = autoconnect;
- g_clear_error(&error);
-
str = g_key_file_get_string(keyfile,
service->identifier, "Failure", NULL);
if (str != NULL) {
service->error = string2error(str);
g_free(str);
}
+ /* fall through */
+
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ autoconnect = g_key_file_get_boolean(keyfile,
+ service->identifier, "AutoConnect", &error);
+ if (error == NULL)
+ service->autoconnect = autoconnect;
+ g_clear_error(&error);
break;
}
switch (service->type) {
case CONNMAN_SERVICE_TYPE_UNKNOWN:
case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_ETHERNET:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_GADGET:
g_key_file_set_boolean(keyfile, service->identifier,
"Favorite", service->favorite);
- if (service->favorite == TRUE)
- g_key_file_set_boolean(keyfile, service->identifier,
- "AutoConnect", service->autoconnect);
-
if (service->state_ipv4 == CONNMAN_SERVICE_STATE_FAILURE ||
service->state_ipv6 == CONNMAN_SERVICE_STATE_FAILURE) {
const char *failure = error2string(service->error);
g_key_file_remove_key(keyfile, service->identifier,
"Failure", NULL);
}
+ /* fall through */
+
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ if (service->favorite == TRUE)
+ g_key_file_set_boolean(keyfile, service->identifier,
+ "AutoConnect", service->autoconnect);
break;
}
return err;
}
-static guint changed_timeout = 0;
-
-static gboolean notify_services_changed(gpointer user_data)
-{
- changed_timeout = 0;
-
- connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
- CONNMAN_MANAGER_INTERFACE, "Services",
- DBUS_TYPE_OBJECT_PATH, __connman_service_list,
- NULL);
-
- return FALSE;
-}
-
-static void services_changed(gboolean delayed)
-{
- DBG("");
-
- if (changed_timeout > 0) {
- g_source_remove(changed_timeout);
- changed_timeout = 0;
- }
-
- if (__connman_connection_update_gateway() == TRUE) {
- notify_services_changed(NULL);
- return;
- }
-
- if (delayed == FALSE) {
- notify_services_changed(NULL);
- return;
- }
-
- changed_timeout = g_timeout_add_seconds(1, notify_services_changed,
- NULL);
-}
-
static enum connman_service_state combine_state(
enum connman_service_state state_a,
enum connman_service_state state_b)
}
}
-static void nameserver_del_routes(int index, char **nameservers)
+static void nameserver_del_routes(int index, char **nameservers,
+ enum connman_ipconfig_type type)
{
int i, ret, family;
struct addrinfo hints;
else
family = addr->ai_family;
- if (family == AF_INET)
- connman_inet_del_host_route(index, nameservers[i]);
- else if (family == AF_INET6)
- connman_inet_del_ipv6_host_route(index,
+ switch (family) {
+ case AF_INET:
+ if (type != CONNMAN_IPCONFIG_TYPE_IPV6)
+ connman_inet_del_host_route(index,
+ nameservers[i]);
+ break;
+ case AF_INET6:
+ if (type != CONNMAN_IPCONFIG_TYPE_IPV4)
+ connman_inet_del_ipv6_host_route(index,
nameservers[i]);
+ break;
+ }
freeaddrinfo(addr);
}
}
}
-void __connman_service_nameserver_del_routes(struct connman_service *service)
+void __connman_service_nameserver_del_routes(struct connman_service *service,
+ enum connman_ipconfig_type type)
{
int index = -1;
index = connman_provider_get_index(service->provider);
if (service->nameservers_config != NULL)
- nameserver_del_routes(index, service->nameservers_config);
+ nameserver_del_routes(index, service->nameservers_config,
+ type);
else if (service->nameservers != NULL)
- nameserver_del_routes(index, service->nameservers);
+ nameserver_del_routes(index, service->nameservers, type);
}
static struct connman_stats *stats_get(struct connman_service *service)
append_provider, service);
}
-static void append_struct(gpointer value, gpointer user_data)
+static void append_struct_service(DBusMessageIter *iter,
+ connman_dbus_append_cb_t function,
+ struct connman_service *service)
{
- struct connman_service *service = value;
- DBusMessageIter *iter = user_data;
DBusMessageIter entry, dict;
- if (service->path == NULL)
- return;
-
dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
&service->path);
connman_dbus_dict_open(&entry, &dict);
- append_properties(&dict, TRUE, service);
+ if (function != NULL)
+ function(&dict, service);
connman_dbus_dict_close(&entry, &dict);
dbus_message_iter_close_container(iter, &entry);
}
+static void append_dict_properties(DBusMessageIter *dict, void *user_data)
+{
+ struct connman_service *service = user_data;
+
+ append_properties(dict, TRUE, service);
+}
+
+static void append_struct(gpointer value, gpointer user_data)
+{
+ struct connman_service *service = value;
+ DBusMessageIter *iter = user_data;
+
+ if (service->path == NULL)
+ return;
+
+ append_struct_service(iter, append_dict_properties, service);
+}
+
void __connman_service_list_struct(DBusMessageIter *iter)
{
g_sequence_foreach(service_list, append_struct, iter);
dbus_message_iter_get_basic(&entry, &key);
dbus_message_iter_next(&entry);
- if (dbus_message_iter_get_arg_type(&entry) !=
- DBUS_TYPE_VARIANT)
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
goto error;
dbus_message_iter_recurse(&entry, &variant);
+
type = dbus_message_iter_get_arg_type(&variant);
if (g_str_equal(key, "Method") == TRUE) {
if (dbus_message_iter_init(msg, &iter) == FALSE)
return __connman_error_invalid_arguments(msg);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
dbus_message_iter_get_basic(&iter, &name);
dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return __connman_error_invalid_arguments(msg);
+
dbus_message_iter_recurse(&iter, &value);
type = dbus_message_iter_get_arg_type(&value);
gw = __connman_ipconfig_get_gateway_from_index(index);
if (gw && strlen(gw))
- __connman_service_nameserver_del_routes(service);
+ __connman_service_nameserver_del_routes(service,
+ CONNMAN_IPCONFIG_TYPE_ALL);
dbus_message_iter_recurse(&value, &entry);
downgrade_state(target);
}
- services_changed(FALSE);
+ __connman_connection_update_gateway();
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
static struct _services_notify {
int id;
- GSList *added;
- GSList *removed;
+ GHashTable *add;
+ GHashTable *remove;
} *services_notify;
+static void append_removed(gpointer key, gpointer value, gpointer user_data)
+{
+ char *objpath = key;
+ DBusMessageIter *iter = user_data;
+
+ DBG("removed %s", objpath);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
+}
+
static void service_send_removed(void)
{
DBusMessage *signal;
DBusMessageIter iter, array;
- GSList *list, *next;
-
- if (services_notify->removed == NULL)
- return;
signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "ServicesRemoved");
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
- list = services_notify->removed;
- services_notify->removed = NULL;
+ g_hash_table_foreach(services_notify->remove, append_removed, &array);
- while (list != NULL) {
- char *path = list->data;
- DBG("removing %s", path);
- next = list->next;
- dbus_message_iter_append_basic(&array,
- DBUS_TYPE_OBJECT_PATH, &list->data);
- g_free(list->data);
- g_slist_free_1(list);
- list = next;
- }
dbus_message_iter_close_container(&iter, &array);
dbus_connection_send(connection, signal, NULL);
dbus_message_unref(signal);
+
+ g_hash_table_remove_all(services_notify->remove);
}
-static void append_service_structs(DBusMessageIter *iter, void *user_data)
+static void service_send_added_foreach(gpointer data, gpointer user_data)
{
- GSList *list = user_data;
- GSList *next;
+ struct connman_service *service = data;
+ DBusMessageIter *iter = user_data;
+
+ if (service == NULL || service->path == NULL) {
+ DBG("service %p or path is NULL", service);
+ return;
+ }
+
+ DBG("added %s", service->path);
- while (list != NULL) {
- struct connman_service *srv = list->data;
- DBG("adding %s", srv->path);
- next = list->next;
- append_struct(list->data, iter);
- g_slist_free_1(list);
- list = next;
+ if (g_hash_table_lookup(services_notify->add, service->path) != NULL) {
+ append_struct(service, iter);
+ g_hash_table_remove(services_notify->add, service->path);
+ } else {
+ append_struct_service(iter, NULL, service);
}
}
+static void service_send_added_ordered(DBusMessageIter *iter, void *user_data)
+{
+ g_sequence_foreach(service_list, service_send_added_foreach, iter);
+}
+
static void service_send_added(void)
{
DBusMessage *signal;
- GSList *list;
-
- if (services_notify->added == NULL)
- return;
signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "ServicesAdded");
if (signal == NULL)
return;
- list = services_notify->added;
- services_notify->added = NULL;
__connman_dbus_append_objpath_dict_array(signal,
- append_service_structs, list);
+ service_send_added_ordered, NULL);
dbus_connection_send(connection, signal, NULL);
dbus_message_unref(signal);
+
+ g_hash_table_remove_all(services_notify->add);
}
static gboolean service_send_signals(gpointer data)
{
- service_send_removed();
- service_send_added();
+ if (g_hash_table_size(services_notify->remove) > 0)
+ service_send_removed();
+
+ if (g_hash_table_size(services_notify->add) > 0)
+ service_send_added();
services_notify->id = 0;
return FALSE;
{
DBG("service %p", service);
- services_notify->added = g_slist_prepend(services_notify->added,
- service);
+ g_hash_table_remove(services_notify->remove, service->path);
+ g_hash_table_insert(services_notify->add, service->path, service);
service_schedule_signals();
}
static void service_schedule_removed(struct connman_service *service)
{
- GSList *list;
-
- DBG("service %p", service);
+ DBG("service %p %s", service, service->path);
if (service == NULL || service->path == NULL) {
DBG("service %p or path is NULL", service);
return;
}
- for (list = services_notify->added; list != NULL; list = list->next) {
- struct connman_service *srv = list->data;
- if (service == srv) {
- DBG("delete service %p from added list", srv);
- break;
- }
- }
-
- if (list != NULL)
- services_notify->added =
- g_slist_delete_link(services_notify->added, list);
-
- services_notify->removed = g_slist_prepend(services_notify->removed,
- g_strdup(service->path));
+ g_hash_table_remove(services_notify->add, service->path);
+ g_hash_table_insert(services_notify->remove, g_strdup(service->path),
+ NULL);
service_schedule_signals();
}
service->path = NULL;
if (path != NULL) {
- services_changed(FALSE);
+ __connman_connection_update_gateway();
g_dbus_unregister_interface(connection, path,
CONNMAN_SERVICE_INTERFACE);
}
+connman_bool_t __connman_service_is_connected_state(struct connman_service *service,
+ enum connman_ipconfig_type type)
+{
+ if (service == NULL)
+ return FALSE;
+
+ switch (type) {
+ case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
+ break;
+ case CONNMAN_IPCONFIG_TYPE_IPV4:
+ return is_connected_state(service, service->state_ipv4);
+ case CONNMAN_IPCONFIG_TYPE_IPV6:
+ return is_connected_state(service, service->state_ipv6);
+ }
+
+ return FALSE;
+}
enum connman_service_security __connman_service_get_security(struct connman_service *service)
{
if (service == NULL)
g_sequence_sort_changed(iter, service_compare, NULL);
- services_changed(FALSE);
+ __connman_connection_update_gateway();
return 0;
}
__connman_service_connect(service);
else {
service_complete(service);
- services_changed(FALSE);
+ __connman_connection_update_gateway();
__connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
}
}
if (values_received == FALSE || service->hidden == TRUE) {
service_complete(service);
- services_changed(FALSE);
+ __connman_connection_update_gateway();
__connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
return;
}
if (iter != NULL)
g_sequence_sort_changed(iter, service_compare, NULL);
- services_changed(FALSE);
+ __connman_connection_update_gateway();
if (new_state == CONNMAN_SERVICE_STATE_ONLINE)
default_changed();
int __connman_service_indicate_default(struct connman_service *service)
{
- DBG("service %p", service);
+ struct connman_service *current = get_default();
+
+ DBG("service %p default %p", service, current);
+
+ if (current == service)
+ return 0;
default_changed();
if (iter != NULL)
g_sequence_sort_changed(iter, service_compare, NULL);
- services_changed(TRUE);
+ __connman_connection_update_gateway();
return 0;
}
if (service->path != NULL) {
update_from_network(service, network);
- services_changed(TRUE);
+ __connman_connection_update_gateway();
return service;
}
service_list = g_sequence_new(service_free);
services_notify = g_new0(struct _services_notify, 1);
+ services_notify->remove = g_hash_table_new_full(g_str_hash,
+ g_str_equal, g_free, NULL);
+ services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
return 0;
}
if (services_notify->id != 0) {
g_source_remove(services_notify->id);
service_send_signals(NULL);
+ g_hash_table_destroy(services_notify->remove);
+ g_hash_table_destroy(services_notify->add);
}
g_free(services_notify);