* dbus/dbus-auth.c (client_try_next_mechanism): Remove logic to
[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 2.0
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_ALLOW_MORE_HANDLERS;
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  * @returns the handler
193  */
194 DBusMessageHandler *
195 dbus_message_handler_ref (DBusMessageHandler *handler)
196 {
197   _dbus_return_if_fail (handler != NULL);
198
199   _dbus_atomic_inc (&handler->refcount);
200
201   return handler;
202 }
203
204 /**
205  * Decrements the reference count on a message handler,
206  * freeing the handler if the count reaches 0.
207  *
208  * @param handler the handler
209  */
210 void
211 dbus_message_handler_unref (DBusMessageHandler *handler)
212 {
213   dbus_bool_t last_unref;
214
215   _dbus_return_if_fail (handler != NULL);
216
217   last_unref = (_dbus_atomic_dec (&handler->refcount) == 1);
218   
219   if (last_unref)
220     {
221       DBusList *link;
222       
223       if (handler->free_user_data)
224         (* handler->free_user_data) (handler->user_data);
225        
226       link = _dbus_list_get_first_link (&handler->connections);
227        while (link != NULL)
228          {
229            DBusConnection *connection = link->data;
230
231            _dbus_connection_handler_destroyed_locked (connection, handler);
232            
233            link = _dbus_list_get_next_link (&handler->connections, link);
234          }
235
236        _dbus_list_clear (&handler->connections);
237
238        dbus_free (handler);
239     }
240 }
241
242 /**
243  * Gets the user data for the handler (the same user data
244  * passed to the handler function.)
245  *
246  * @param handler the handler
247  * @returns the user data
248  */
249 void*
250 dbus_message_handler_get_data (DBusMessageHandler *handler)
251 {
252   void* user_data;
253
254   _dbus_return_val_if_fail (handler != NULL, NULL);
255   
256   _DBUS_LOCK (message_handler);
257   user_data = handler->user_data;
258   _DBUS_UNLOCK (message_handler);
259   return user_data;
260 }
261
262 /**
263  * Sets the user data for the handler (the same user data
264  * to be passed to the handler function). Frees any previously-existing
265  * user data with the previous free_user_data function.
266  *
267  * @param handler the handler
268  * @param user_data the user data
269  * @param free_user_data free function for the data
270  */
271 void
272 dbus_message_handler_set_data (DBusMessageHandler *handler,
273                                void               *user_data,
274                                DBusFreeFunction    free_user_data)
275 {
276   DBusFreeFunction old_free_func;
277   void *old_user_data;
278
279   _dbus_return_if_fail (handler != NULL);
280   
281   _DBUS_LOCK (message_handler);
282   old_free_func = handler->free_user_data;
283   old_user_data = handler->user_data;
284
285   handler->user_data = user_data;
286   handler->free_user_data = free_user_data;
287   _DBUS_UNLOCK (message_handler);
288
289   if (old_free_func)
290     (* old_free_func) (old_user_data);
291
292 }
293
294 /**
295  * Sets the handler function. Call dbus_message_handler_set_data()
296  * to set the user data for the function.
297  *
298  * @param handler the handler
299  * @param function the function
300  */
301 void
302 dbus_message_handler_set_function (DBusMessageHandler        *handler,
303                                    DBusHandleMessageFunction  function)
304 {
305   _dbus_return_if_fail (handler != NULL);
306   
307   _DBUS_LOCK (message_handler);
308   handler->function = function;
309   _DBUS_UNLOCK (message_handler);
310 }
311
312 /** @} */
313
314 #ifdef DBUS_BUILD_TESTS
315 static DBusHandlerResult
316 test_handler (DBusMessageHandler *handler,
317               DBusConnection     *connection,
318               DBusMessage        *message,
319               void               *user_data)
320 {
321   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
322 }
323
324 static void
325 free_test_data (void *data)
326 {
327   /* does nothing */
328 }
329
330 /**
331  * @ingroup DBusMessageInternals
332  * Unit test for DBusMessageHandler.
333  *
334  * @returns #TRUE on success.
335  */
336 dbus_bool_t
337 _dbus_message_handler_test (const char *test_data_dir)
338 {
339   DBusMessageHandler *handler;
340
341 #define TEST_DATA ((void*) 0xcafebabe)
342   
343   handler = dbus_message_handler_new (test_handler,
344                                       TEST_DATA,
345                                       free_test_data);
346
347   _dbus_assert (handler != NULL);
348   _dbus_assert (handler->function == test_handler);
349
350   if (dbus_message_handler_get_data (handler) != TEST_DATA)
351     _dbus_assert_not_reached ("got wrong data");
352
353   dbus_message_handler_set_data (handler, NULL, NULL);
354   if (dbus_message_handler_get_data (handler) != NULL)
355     _dbus_assert_not_reached ("got wrong data after set");  
356   
357   dbus_message_handler_set_function (handler, NULL);
358   _dbus_assert (handler->function == NULL);
359
360   dbus_message_handler_ref (handler);
361   dbus_message_handler_unref (handler);
362   dbus_message_handler_unref (handler);
363   
364   return TRUE;
365 }
366 #endif /* DBUS_BUILD_TESTS */