2003-04-24 Havoc Pennington <hp@redhat.com>
[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  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-connection-internal.h"
29
30 /**
31  * @defgroup DBusMessageHandlerInternals DBusMessageHandler implementation details
32  * @ingroup DBusInternals
33  * @brief DBusMessageHandler private implementation details.
34  *
35  * The guts of DBusMessageHandler and its methods.
36  *
37  * @{
38  */
39
40 _DBUS_DEFINE_GLOBAL_LOCK (message_handler);
41
42 /**
43  * @brief Internals of DBusMessageHandler
44  * 
45  * Object that can send and receive messages.
46  */
47 struct DBusMessageHandler
48 {
49   int refcount;                                   /**< reference count */
50
51   DBusHandleMessageFunction function;             /**< handler function */
52   void                     *user_data;            /**< user data for function */
53   DBusFreeFunction          free_user_data;       /**< free the user data */
54
55   DBusList *connections;                          /**< connections we're registered with */
56 };
57
58 /**
59  * Add this connection to the list used by this message handler.
60  * When the message handler goes away, the connection
61  * will be notified.
62  *
63  * @param handler the message handler
64  * @param connection the connection
65  * @returns #FALSE if not enough memory
66  */
67 dbus_bool_t
68 _dbus_message_handler_add_connection (DBusMessageHandler *handler,
69                                       DBusConnection     *connection)
70 {
71   dbus_bool_t res;
72   
73   _DBUS_LOCK (message_handler);
74   /* This is a bit wasteful - we just put the connection in the list
75    * once per time it's added. :-/
76    */
77   if (!_dbus_list_prepend (&handler->connections, connection))
78     res = FALSE;
79   else
80     res = TRUE;
81
82   _DBUS_UNLOCK (message_handler);
83   
84   return res;
85 }
86
87 /**
88  * Reverses the effect of _dbus_message_handler_add_connection().
89  * @param handler the message handler
90  * @param connection the connection
91  */
92 void
93 _dbus_message_handler_remove_connection (DBusMessageHandler *handler,
94                                          DBusConnection     *connection)
95 {
96   _DBUS_LOCK (message_handler);
97   if (!_dbus_list_remove (&handler->connections, connection))
98     _dbus_warn ("Function _dbus_message_handler_remove_connection() called when the connection hadn't been added\n");
99   _DBUS_UNLOCK (message_handler);
100 }
101
102
103 /**
104  * Handles the given message, by dispatching the handler function
105  * for this DBusMessageHandler, if any.
106  * 
107  * @param handler the handler
108  * @param connection the connection that received the message
109  * @param message the message
110  *
111  * @returns what to do with the message
112  */
113 DBusHandlerResult
114 _dbus_message_handler_handle_message (DBusMessageHandler        *handler,
115                                       DBusConnection            *connection,
116                                       DBusMessage               *message)
117 {
118   DBusHandleMessageFunction function;
119   void  *user_data;
120   
121   _DBUS_LOCK (message_handler);
122   function = handler->function;
123   user_data = handler->user_data;
124   _DBUS_UNLOCK (message_handler);
125   
126   /* This function doesn't ref handler/connection/message
127    * since that's done in dbus_connection_dispatch().
128    */
129   if (function != NULL)
130     return (* function) (handler, connection, message, user_data);
131   else
132     return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
133 }
134
135 /** @} */
136
137 /**
138  * @defgroup DBusMessageHandler DBusMessageHandler
139  * @ingroup  DBus
140  * @brief Message processor  
141  *
142  * A DBusMessageHandler is an object that can send and receive
143  * messages. Typically the handler is registered with one or
144  * more DBusConnection objects and processes some types of
145  * messages received from the connection.
146  *
147  * @{
148  */
149
150 /**
151  * @typedef DBusMessageHandler
152  *
153  * Opaque data type representing a message handler.
154  */
155
156 /**
157  * Creates a new message handler. The handler function
158  * may be #NULL for a no-op handler or a handler to
159  * be assigned a function later.
160  *
161  * @param function function to call to handle a message
162  * @param user_data data to pass to the function
163  * @param free_user_data function to call to free the user data
164  * @returns a new DBusMessageHandler or #NULL if no memory.
165  */
166 DBusMessageHandler*
167 dbus_message_handler_new (DBusHandleMessageFunction function,
168                           void                     *user_data,
169                           DBusFreeFunction          free_user_data)
170 {
171   DBusMessageHandler *handler;
172
173   handler = dbus_new (DBusMessageHandler, 1);
174
175   if (handler == NULL)
176     return NULL;
177   
178   handler->refcount = 1;
179   handler->function = function;
180   handler->user_data = user_data;
181   handler->free_user_data = free_user_data;
182   handler->connections = NULL;
183
184   return handler;
185 }
186
187 /**
188  * Increments the reference count on a message handler.
189  *
190  * @param handler the handler
191  */
192 void
193 dbus_message_handler_ref (DBusMessageHandler *handler)
194 {
195   _dbus_return_if_fail (handler != NULL);
196   
197   _DBUS_LOCK (message_handler);
198   _dbus_assert (handler != NULL);
199   
200   handler->refcount += 1;
201   _DBUS_UNLOCK (message_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   int refcount;
214
215   _dbus_return_if_fail (handler != NULL);
216   
217   _DBUS_LOCK (message_handler);
218   
219   _dbus_assert (handler != NULL);
220   _dbus_assert (handler->refcount > 0);
221
222   handler->refcount -= 1;
223   refcount = handler->refcount;
224   
225   _DBUS_UNLOCK (message_handler);
226   
227   if (refcount == 0)
228     {
229       DBusList *link;
230       
231       if (handler->free_user_data)
232         (* handler->free_user_data) (handler->user_data);
233        
234       link = _dbus_list_get_first_link (&handler->connections);
235        while (link != NULL)
236          {
237            DBusConnection *connection = link->data;
238
239            _dbus_connection_handler_destroyed_locked (connection, handler);
240            
241            link = _dbus_list_get_next_link (&handler->connections, link);
242          }
243
244        _dbus_list_clear (&handler->connections);
245
246        dbus_free (handler);
247     }
248 }
249
250 /**
251  * Gets the user data for the handler (the same user data
252  * passed to the handler function.)
253  *
254  * @param handler the handler
255  * @returns the user data
256  */
257 void*
258 dbus_message_handler_get_data (DBusMessageHandler *handler)
259 {
260   void* user_data;
261
262   _dbus_return_val_if_fail (handler != NULL, NULL);
263   
264   _DBUS_LOCK (message_handler);
265   user_data = handler->user_data;
266   _DBUS_UNLOCK (message_handler);
267   return user_data;
268 }
269
270 /**
271  * Sets the user data for the handler (the same user data
272  * to be passed to the handler function). Frees any previously-existing
273  * user data with the previous free_user_data function.
274  *
275  * @param handler the handler
276  * @param user_data the user data
277  * @param free_user_data free function for the data
278  */
279 void
280 dbus_message_handler_set_data (DBusMessageHandler *handler,
281                                void               *user_data,
282                                DBusFreeFunction    free_user_data)
283 {
284   DBusFreeFunction old_free_func;
285   void *old_user_data;
286
287   _dbus_return_if_fail (handler != NULL);
288   
289   _DBUS_LOCK (message_handler);
290   old_free_func = handler->free_user_data;
291   old_user_data = handler->user_data;
292
293   handler->user_data = user_data;
294   handler->free_user_data = free_user_data;
295   _DBUS_UNLOCK (message_handler);
296
297   if (old_free_func)
298     (* old_free_func) (old_user_data);
299
300 }
301
302 /**
303  * Sets the handler function. Call dbus_message_handler_set_data()
304  * to set the user data for the function.
305  *
306  * @param handler the handler
307  * @param function the function
308  */
309 void
310 dbus_message_handler_set_function (DBusMessageHandler        *handler,
311                                    DBusHandleMessageFunction  function)
312 {
313   _dbus_return_if_fail (handler != NULL);
314   
315   _DBUS_LOCK (message_handler);
316   handler->function = function;
317   _DBUS_UNLOCK (message_handler);
318 }
319
320 /** @} */