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