2e8a8b64199d5628d2f949a75dba917106fa5e02
[platform/upstream/dbus.git] / dbus / dbus-message-handler.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message-handler.c Sender/receiver of messages.
3  *
4  * Copyright (C) 2002, 2003 Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-message-handler.h"
26 #include "dbus-list.h"
27 #include "dbus-threads.h"
28 #include "dbus-test.h"
29 #include "dbus-connection-internal.h"
30
31 /**
32  * @defgroup DBusMessageHandlerInternals DBusMessageHandler implementation details
33  * @ingroup DBusInternals
34  * @brief DBusMessageHandler private implementation details.
35  *
36  * The guts of DBusMessageHandler and its methods.
37  *
38  * @{
39  */
40
41 _DBUS_DEFINE_GLOBAL_LOCK (message_handler);
42
43 /**
44  * @brief Internals of DBusMessageHandler
45  * 
46  * Object that can send and receive messages.
47  */
48 struct DBusMessageHandler
49 {
50   DBusAtomic refcount;                            /**< reference count */
51
52   DBusHandleMessageFunction function;             /**< handler function */
53   void                     *user_data;            /**< user data for function */
54   DBusFreeFunction          free_user_data;       /**< free the user data */
55
56   DBusList *connections;                          /**< connections we're registered with */
57 };
58
59 /**
60  * Add this connection to the list used by this message handler.
61  * When the message handler goes away, the connection
62  * will be notified.
63  *
64  * @param handler the message handler
65  * @param connection the connection
66  * @returns #FALSE if not enough memory
67  */
68 dbus_bool_t
69 _dbus_message_handler_add_connection (DBusMessageHandler *handler,
70                                       DBusConnection     *connection)
71 {
72   dbus_bool_t res;
73   
74   _DBUS_LOCK (message_handler);
75   /* This is a bit wasteful - we just put the connection in the list
76    * once per time it's added. :-/
77    */
78   if (!_dbus_list_prepend (&handler->connections, connection))
79     res = FALSE;
80   else
81     res = TRUE;
82
83   _DBUS_UNLOCK (message_handler);
84   
85   return res;
86 }
87
88 /**
89  * Reverses the effect of _dbus_message_handler_add_connection().
90  * @param handler the message handler
91  * @param connection the connection
92  */
93 void
94 _dbus_message_handler_remove_connection (DBusMessageHandler *handler,
95                                          DBusConnection     *connection)
96 {
97   _DBUS_LOCK (message_handler);
98   if (!_dbus_list_remove (&handler->connections, connection))
99     _dbus_warn ("Function _dbus_message_handler_remove_connection() called when the connection hadn't been added\n");
100   _DBUS_UNLOCK (message_handler);
101 }
102
103
104 /**
105  * Handles the given message, by dispatching the handler function
106  * for this DBusMessageHandler, if any.
107  * 
108  * @param handler the handler
109  * @param connection the connection that received the message
110  * @param message the message
111  *
112  * @returns what to do with the message
113  */
114 DBusHandlerResult
115 _dbus_message_handler_handle_message (DBusMessageHandler        *handler,
116                                       DBusConnection            *connection,
117                                       DBusMessage               *message)
118 {
119   DBusHandleMessageFunction function;
120   void  *user_data;
121   
122   _DBUS_LOCK (message_handler);
123   function = handler->function;
124   user_data = handler->user_data;
125   _DBUS_UNLOCK (message_handler);
126   
127   /* This function doesn't ref handler/connection/message
128    * since that's done in dbus_connection_dispatch().
129    */
130   if (function != NULL)
131     return (* function) (handler, connection, message, user_data);
132   else
133     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
134 }
135
136 /** @} */
137
138 /**
139  * @defgroup DBusMessageHandler DBusMessageHandler
140  * @ingroup  DBus
141  * @brief Message processor  
142  *
143  * A DBusMessageHandler is an object that can send and receive
144  * messages. Typically the handler is registered with one or
145  * more DBusConnection objects and processes some types of
146  * messages received from the connection.
147  *
148  * @{
149  */
150
151 /**
152  * @typedef DBusMessageHandler
153  *
154  * Opaque data type representing a message handler.
155  */
156
157 /**
158  * Creates a new message handler. The handler function
159  * may be #NULL for a no-op handler or a handler to
160  * be assigned a function later.
161  *
162  * @param function function to call to handle a message
163  * @param user_data data to pass to the function
164  * @param free_user_data function to call to free the user data
165  * @returns a new DBusMessageHandler or #NULL if no memory.
166  */
167 DBusMessageHandler*
168 dbus_message_handler_new (DBusHandleMessageFunction function,
169                           void                     *user_data,
170                           DBusFreeFunction          free_user_data)
171 {
172   DBusMessageHandler *handler;
173
174   handler = dbus_new (DBusMessageHandler, 1);
175
176   if (handler == NULL)
177     return NULL;
178   
179   handler->refcount.value = 1;
180   handler->function = function;
181   handler->user_data = user_data;
182   handler->free_user_data = free_user_data;
183   handler->connections = NULL;
184
185   return handler;
186 }
187
188 /**
189  * Increments the reference count on a message handler.
190  *
191  * @param handler the handler
192  */
193 void
194 dbus_message_handler_ref (DBusMessageHandler *handler)
195 {
196   _dbus_return_if_fail (handler != NULL);
197
198   _dbus_atomic_inc (&handler->refcount);
199 }
200
201 /**
202  * Decrements the reference count on a message handler,
203  * freeing the handler if the count reaches 0.
204  *
205  * @param handler the handler
206  */
207 void
208 dbus_message_handler_unref (DBusMessageHandler *handler)
209 {
210   dbus_bool_t last_unref;
211
212   _dbus_return_if_fail (handler != NULL);
213
214   last_unref = (_dbus_atomic_dec (&handler->refcount) == 1);
215   
216   if (last_unref)
217     {
218       DBusList *link;
219       
220       if (handler->free_user_data)
221         (* handler->free_user_data) (handler->user_data);
222        
223       link = _dbus_list_get_first_link (&handler->connections);
224        while (link != NULL)
225          {
226            DBusConnection *connection = link->data;
227
228            _dbus_connection_handler_destroyed_locked (connection, handler);
229            
230            link = _dbus_list_get_next_link (&handler->connections, link);
231          }
232
233        _dbus_list_clear (&handler->connections);
234
235        dbus_free (handler);
236     }
237 }
238
239 /**
240  * Gets the user data for the handler (the same user data
241  * passed to the handler function.)
242  *
243  * @param handler the handler
244  * @returns the user data
245  */
246 void*
247 dbus_message_handler_get_data (DBusMessageHandler *handler)
248 {
249   void* user_data;
250
251   _dbus_return_val_if_fail (handler != NULL, NULL);
252   
253   _DBUS_LOCK (message_handler);
254   user_data = handler->user_data;
255   _DBUS_UNLOCK (message_handler);
256   return user_data;
257 }
258
259 /**
260  * Sets the user data for the handler (the same user data
261  * to be passed to the handler function). Frees any previously-existing
262  * user data with the previous free_user_data function.
263  *
264  * @param handler the handler
265  * @param user_data the user data
266  * @param free_user_data free function for the data
267  */
268 void
269 dbus_message_handler_set_data (DBusMessageHandler *handler,
270                                void               *user_data,
271                                DBusFreeFunction    free_user_data)
272 {
273   DBusFreeFunction old_free_func;
274   void *old_user_data;
275
276   _dbus_return_if_fail (handler != NULL);
277   
278   _DBUS_LOCK (message_handler);
279   old_free_func = handler->free_user_data;
280   old_user_data = handler->user_data;
281
282   handler->user_data = user_data;
283   handler->free_user_data = free_user_data;
284   _DBUS_UNLOCK (message_handler);
285
286   if (old_free_func)
287     (* old_free_func) (old_user_data);
288
289 }
290
291 /**
292  * Sets the handler function. Call dbus_message_handler_set_data()
293  * to set the user data for the function.
294  *
295  * @param handler the handler
296  * @param function the function
297  */
298 void
299 dbus_message_handler_set_function (DBusMessageHandler        *handler,
300                                    DBusHandleMessageFunction  function)
301 {
302   _dbus_return_if_fail (handler != NULL);
303   
304   _DBUS_LOCK (message_handler);
305   handler->function = function;
306   _DBUS_UNLOCK (message_handler);
307 }
308
309 /** @} */
310
311 #ifdef DBUS_BUILD_TESTS
312 static DBusHandlerResult
313 test_handler (DBusMessageHandler *handler,
314               DBusConnection     *connection,
315               DBusMessage        *message,
316               void               *user_data)
317 {
318   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
319 }
320
321 static void
322 free_test_data (void *data)
323 {
324   /* does nothing */
325 }
326
327 /**
328  * @ingroup DBusMessageHandlerInternals
329  * Unit test for DBusMessageHandler.
330  *
331  * @returns #TRUE on success.
332  */
333 dbus_bool_t
334 _dbus_message_handler_test (const char *test_data_dir)
335 {
336   DBusMessageHandler *handler;
337
338 #define TEST_DATA ((void*) 0xcafebabe)
339   
340   handler = dbus_message_handler_new (test_handler,
341                                       TEST_DATA,
342                                       free_test_data);
343
344   _dbus_assert (handler != NULL);
345   _dbus_assert (handler->function == test_handler);
346
347   if (dbus_message_handler_get_data (handler) != TEST_DATA)
348     _dbus_assert_not_reached ("got wrong data");
349
350   dbus_message_handler_set_data (handler, NULL, NULL);
351   if (dbus_message_handler_get_data (handler) != NULL)
352     _dbus_assert_not_reached ("got wrong data after set");  
353   
354   dbus_message_handler_set_function (handler, NULL);
355   _dbus_assert (handler->function == NULL);
356
357   dbus_message_handler_ref (handler);
358   dbus_message_handler_unref (handler);
359   dbus_message_handler_unref (handler);
360   
361   return TRUE;
362 }
363 #endif /* DBUS_BUILD_TESTS */