5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 static DBusConnection *connection;
34 struct _peer_service {
39 GBytes *specification;
46 struct _peer_service_owner {
52 static struct connman_peer_driver *peer_driver;
54 static GHashTable *owners_map;
55 static GHashTable *services_map;
56 static int peer_master;
58 static void reply_pending(struct _peer_service *service, int error)
60 if (!service->pending)
63 connman_dbus_reply_pending(service->pending, error, NULL);
64 service->pending = NULL;
67 static struct _peer_service *find_peer_service(GBytes *specification,
68 GBytes *query, int version,
69 const char *owner, bool remove)
71 struct _peer_service *service = NULL;
72 struct _peer_service_owner *ps_owner;
75 ps_owner = g_hash_table_lookup(services_map, specification);
79 if (owner && g_strcmp0(owner, ps_owner->owner) != 0)
82 for (list = ps_owner->services; list; list = list->next) {
85 if (service->specification == specification)
89 if (!service->version)
91 if (version != service->version)
98 if (g_bytes_equal(service->query, query))
102 if (g_bytes_equal(service->specification, specification))
110 ps_owner->services = g_list_delete_link(ps_owner->services,
116 static void unregister_peer_service(struct _peer_service *service)
118 gsize spec_length, query_length = 0;
119 const void *spec, *query = NULL;
121 if (!peer_driver || !service->specification)
124 spec = g_bytes_get_data(service->specification, &spec_length);
126 query = g_bytes_get_data(service->query, &query_length);
128 peer_driver->unregister_service(spec, spec_length, query,
129 query_length, service->version);
132 static void remove_peer_service(gpointer user_data)
134 struct _peer_service *service = user_data;
136 reply_pending(service, ECONNABORTED);
138 if (service->registered)
139 unregister_peer_service(service);
141 if (service->specification) {
142 if (service->owner) {
143 find_peer_service(service->specification,
144 service->query, service->version,
145 service->owner, true);
148 g_hash_table_remove(services_map, service->specification);
149 g_bytes_unref(service->specification);
153 g_bytes_unref(service->query);
161 static void apply_peer_service_removal(gpointer user_data)
163 struct _peer_service *service = user_data;
165 service->owner = NULL;
166 remove_peer_service(user_data);
169 static void remove_peer_service_owner(gpointer user_data)
171 struct _peer_service_owner *ps_owner = user_data;
173 DBG("owner %s", ps_owner->owner);
175 if (ps_owner->watch > 0)
176 g_dbus_remove_watch(connection, ps_owner->watch);
178 if (ps_owner->services) {
179 g_list_free_full(ps_owner->services,
180 apply_peer_service_removal);
183 g_free(ps_owner->owner);
187 static void owner_disconnect(DBusConnection *conn, void *user_data)
189 struct _peer_service_owner *ps_owner = user_data;
192 g_hash_table_remove(owners_map, ps_owner->owner);
195 static void service_registration_result(int result, void *user_data)
197 struct _peer_service *service = user_data;
199 reply_pending(service, -result);
201 if (service->registered)
205 service->registered = true;
211 remove_peer_service(service);
214 static int register_peer_service(struct _peer_service *service)
216 gsize spec_length, query_length = 0;
217 const void *spec, *query = NULL;
222 spec = g_bytes_get_data(service->specification, &spec_length);
224 query = g_bytes_get_data(service->query, &query_length);
226 return peer_driver->register_service(spec, spec_length, query,
227 query_length, service->version,
228 service_registration_result, service);
231 static void register_all_services(gpointer key, gpointer value,
234 struct _peer_service_owner *ps_owner = value;
237 for (list = ps_owner->services; list; list = list->next) {
238 struct _peer_service *service = list->data;
240 if (service->registered)
241 register_peer_service(service);
245 void __connman_peer_service_set_driver(struct connman_peer_driver *driver)
247 peer_driver = driver;
251 g_hash_table_foreach(owners_map, register_all_services, NULL);
254 int __connman_peer_service_register(const char *owner, DBusMessage *msg,
255 const unsigned char *specification,
256 int specification_length,
257 const unsigned char *query,
258 int query_length, int version,
261 struct _peer_service_owner *ps_owner;
262 GBytes *spec, *query_spec = NULL;
263 struct _peer_service *service;
267 DBG("owner %s - spec %p/length %d - query %p/length %d - version %d",
268 owner,specification, specification_length,
269 query, query_length, version);
271 if (!specification || specification_length == 0)
274 ps_owner = g_hash_table_lookup(owners_map, owner);
276 ps_owner = g_try_new0(struct _peer_service_owner, 1);
280 ps_owner->owner = g_strdup(owner);
281 ps_owner->watch = g_dbus_add_disconnect_watch(connection,
282 owner, owner_disconnect,
284 g_hash_table_insert(owners_map, ps_owner->owner, ps_owner);
288 spec = g_bytes_new(specification, specification_length);
290 query_spec = g_bytes_new(query, query_length);
292 service = find_peer_service(spec, query_spec, version, NULL, false);
294 DBG("Found one existing service %p", service);
296 if (g_strcmp0(service->owner, owner))
299 if (service->pending)
308 service = g_try_new0(struct _peer_service, 1);
314 service->owner = ps_owner->owner;
315 service->specification = spec;
316 service->query = query_spec;
317 service->version = version;
318 service->master = master;
320 g_hash_table_insert(services_map, spec, ps_owner);
321 spec = query_spec = NULL;
323 ret = register_peer_service(service);
324 if (ret != 0 && ret != -EINPROGRESS)
326 else if (ret == -EINPROGRESS)
327 service->pending = dbus_message_ref(msg);
329 service->registered = true;
334 ps_owner->services = g_list_prepend(ps_owner->services, service);
341 g_bytes_unref(query_spec);
344 remove_peer_service(service);
347 g_hash_table_remove(owners_map, ps_owner->owner);
352 int __connman_peer_service_unregister(const char *owner,
353 const unsigned char *specification,
354 int specification_length,
355 const unsigned char *query,
356 int query_length, int version)
358 struct _peer_service_owner *ps_owner;
359 GBytes *spec, *query_spec = NULL;
360 struct _peer_service *service;
362 DBG("owner %s - spec %p/length %d - query %p/length %d - version %d",
363 owner,specification, specification_length,
364 query, query_length, version);
366 ps_owner = g_hash_table_lookup(owners_map, owner);
370 spec = g_bytes_new(specification, specification_length);
372 query_spec = g_bytes_new(query, query_length);
374 service = find_peer_service(spec, query_spec, version, owner, true);
377 g_bytes_unref(query_spec);
382 remove_peer_service(service);
384 if (!ps_owner->services)
385 g_hash_table_remove(owners_map, ps_owner->owner);
390 bool connman_peer_service_is_master(void)
392 if (!peer_master || !peer_driver)
398 int __connman_peer_service_init(void)
401 connection = connman_dbus_get_connection();
407 owners_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
408 remove_peer_service_owner);
409 services_map = g_hash_table_new_full(g_bytes_hash, g_bytes_equal,
416 void __connman_peer_service_cleanup(void)
423 g_hash_table_destroy(owners_map);
424 g_hash_table_destroy(services_map);
427 dbus_connection_unref(connection);