Add framework for counter callbacks
[platform/upstream/connman.git] / src / counter.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <gdbus.h>
27
28 #include "connman.h"
29
30 static DBusConnection *connection;
31
32 static GHashTable *counter_table;
33 static GHashTable *owner_mapping;
34
35 struct connman_counter {
36         char *owner;
37         char *path;
38         guint timeout;
39         guint watch;
40 };
41
42 static void remove_counter(gpointer user_data)
43 {
44         struct connman_counter *counter = user_data;
45
46         DBG("owner %s path %s", counter->owner, counter->path);
47
48         if (counter->watch > 0)
49                 g_dbus_remove_watch(connection, counter->watch);
50
51         if (counter->timeout > 0)
52                 g_source_remove(counter->timeout);
53
54         g_free(counter->owner);
55         g_free(counter->path);
56         g_free(counter);
57 }
58
59 static void owner_disconnect(DBusConnection *connection, void *user_data)
60 {
61         struct connman_counter *counter = user_data;
62
63         DBG("owner %s path %s", counter->owner, counter->path);
64
65         g_hash_table_remove(owner_mapping, counter->owner);
66         g_hash_table_remove(counter_table, counter->path);
67 }
68
69 static gboolean counter_timeout(gpointer user_data)
70 {
71         struct connman_counter *counter = user_data;
72         DBusMessage *message;
73
74         DBG("owner %s path %s", counter->owner, counter->path);
75
76         message = dbus_message_new_method_call(counter->owner, counter->path,
77                                         CONNMAN_COUNTER_INTERFACE, "Usage");
78         if (message == NULL)
79                 return TRUE;
80
81         dbus_message_set_no_reply(message, TRUE);
82
83         g_dbus_send_message(connection, message);
84
85         return TRUE;
86 }
87
88 int __connman_counter_register(const char *owner, const char *path,
89                                                 unsigned int interval)
90 {
91         struct connman_counter *counter;
92
93         DBG("owner %s path %s interval %u", owner, path, interval);
94
95         counter = g_hash_table_lookup(counter_table, path);
96         if (counter != NULL)
97                 return -EEXIST;
98
99         counter = g_try_new0(struct connman_counter, 1);
100         if (counter == NULL)
101                 return -ENOMEM;
102
103         counter->owner = g_strdup(owner);
104         counter->path = g_strdup(path);
105
106         g_hash_table_replace(counter_table, counter->path, counter);
107         g_hash_table_replace(owner_mapping, counter->owner, counter);
108
109         counter->timeout = g_timeout_add_seconds(interval,
110                                                 counter_timeout, counter);
111
112         counter->watch = g_dbus_add_disconnect_watch(connection, owner,
113                                         owner_disconnect, counter, NULL);
114
115         return 0;
116 }
117
118 int __connman_counter_unregister(const char *owner, const char *path)
119 {
120         struct connman_counter *counter;
121
122         DBG("owner %s path %s", owner, path);
123
124         counter = g_hash_table_lookup(counter_table, path);
125         if (counter == NULL)
126                 return -ESRCH;
127
128         if (g_strcmp0(owner, counter->owner) != 0)
129                 return -EACCES;
130
131         g_hash_table_remove(owner_mapping, counter->owner);
132         g_hash_table_remove(counter_table, counter->path);
133
134         return 0;
135 }
136
137 static void release_counter(gpointer key, gpointer value, gpointer user_data)
138 {
139         struct connman_counter *counter = value;
140         DBusMessage *message;
141
142         DBG("owner %s path %s", counter->owner, counter->path);
143
144         message = dbus_message_new_method_call(counter->owner, counter->path,
145                                         CONNMAN_COUNTER_INTERFACE, "Release");
146         if (message == NULL)
147                 return;
148
149         dbus_message_set_no_reply(message, TRUE);
150
151         g_dbus_send_message(connection, message);
152 }
153
154 int __connman_counter_init(void)
155 {
156         DBG("");
157
158         connection = connman_dbus_get_connection();
159         if (connection == NULL)
160                 return -1;
161
162         counter_table = g_hash_table_new_full(g_str_hash, g_str_equal,
163                                                         NULL, remove_counter);
164         owner_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
165                                                                 NULL, NULL);
166
167         return 0;
168 }
169
170 void __connman_counter_cleanup(void)
171 {
172         DBG("");
173
174         if (connection == NULL)
175                 return;
176
177         g_hash_table_foreach(counter_table, release_counter, NULL);
178
179         g_hash_table_destroy(owner_mapping);
180         g_hash_table_destroy(counter_table);
181
182         dbus_connection_unref(connection);
183 }