2003-04-22 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_LOCK (message_handler);
196   _dbus_assert (handler != NULL);
197   
198   handler->refcount += 1;
199   _DBUS_UNLOCK (message_handler);
200 }
201
202 /**
203  * Decrements the reference count on a message handler,
204  * freeing the handler if the count reaches 0.
205  *
206  * @param handler the handler
207  */
208 void
209 dbus_message_handler_unref (DBusMessageHandler *handler)
210 {
211   int refcount;
212   
213   _DBUS_LOCK (message_handler);
214   
215   _dbus_assert (handler != NULL);
216   _dbus_assert (handler->refcount > 0);
217
218   handler->refcount -= 1;
219   refcount = handler->refcount;
220   
221   _DBUS_UNLOCK (message_handler);
222   
223   if (refcount == 0)
224     {
225       DBusList *link;
226       
227       if (handler->free_user_data)
228         (* handler->free_user_data) (handler->user_data);
229        
230       link = _dbus_list_get_first_link (&handler->connections);
231        while (link != NULL)
232          {
233            DBusConnection *connection = link->data;
234
235            _dbus_connection_handler_destroyed_locked (connection, handler);
236            
237            link = _dbus_list_get_next_link (&handler->connections, link);
238          }
239
240        _dbus_list_clear (&handler->connections);
241
242        dbus_free (handler);
243     }
244 }
245
246 /**
247  * Gets the user data for the handler (the same user data
248  * passed to the handler function.)
249  *
250  * @param handler the handler
251  * @returns the user data
252  */
253 void*
254 dbus_message_handler_get_data (DBusMessageHandler *handler)
255 {
256   void* user_data;
257   _DBUS_LOCK (message_handler);
258   user_data = handler->user_data;
259   _DBUS_UNLOCK (message_handler);
260   return user_data;
261 }
262
263 /**
264  * Sets the user data for the handler (the same user data
265  * to be passed to the handler function). Frees any previously-existing
266  * user data with the previous free_user_data function.
267  *
268  * @param handler the handler
269  * @param user_data the user data
270  * @param free_user_data free function for the data
271  */
272 void
273 dbus_message_handler_set_data (DBusMessageHandler *handler,
274                                void               *user_data,
275                                DBusFreeFunction    free_user_data)
276 {
277   DBusFreeFunction old_free_func;
278   void *old_user_data;
279   
280   _DBUS_LOCK (message_handler);
281   old_free_func = handler->free_user_data;
282   old_user_data = handler->user_data;
283
284   handler->user_data = user_data;
285   handler->free_user_data = free_user_data;
286   _DBUS_UNLOCK (message_handler);
287
288   if (old_free_func)
289     (* old_free_func) (old_user_data);
290
291 }
292
293 /**
294  * Sets the handler function. Call dbus_message_handler_set_data()
295  * to set the user data for the function.
296  *
297  * @param handler the handler
298  * @param function the function
299  */
300 void
301 dbus_message_handler_set_function (DBusMessageHandler        *handler,
302                                    DBusHandleMessageFunction  function)
303 {
304   _DBUS_LOCK (message_handler);
305   handler->function = function;
306   _DBUS_UNLOCK (message_handler);
307 }
308
309 /** @} */