4319e5fe4ef21afe9d3387518438670e59770ae7
[platform/upstream/dbus.git] / bus / bus.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* bus.c  message bus context object
3  *
4  * Copyright (C) 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 "bus.h"
25 #include "loop.h"
26 #include "activation.h"
27 #include "connection.h"
28 #include "services.h"
29 #include "utils.h"
30 #include <dbus/dbus-internals.h>
31
32 struct BusContext
33 {
34   int refcount;
35   char *address;  
36   DBusServer *server;
37   BusConnections *connections;
38   BusActivation *activation;
39   BusRegistry *registry;
40 };
41
42 static void
43 server_watch_callback (DBusWatch     *watch,
44                        unsigned int   condition,
45                        void          *data)
46 {
47   BusContext *context = data;
48
49   dbus_server_handle_watch (context->server, watch, condition);  
50 }
51
52 static dbus_bool_t
53 add_server_watch (DBusWatch  *watch,
54                   BusContext *context)
55 {
56   return bus_loop_add_watch (watch, server_watch_callback, context,
57                              NULL);
58 }
59
60 static void
61 remove_server_watch (DBusWatch  *watch,
62                      BusContext *context)
63 {
64   bus_loop_remove_watch (watch, server_watch_callback, context);
65 }
66
67
68 static void
69 server_timeout_callback (DBusTimeout   *timeout,
70                          void          *data)
71 {
72   dbus_timeout_handle (timeout);
73 }
74
75 static dbus_bool_t
76 add_server_timeout (DBusTimeout *timeout,
77                     BusContext  *context)
78 {
79   return bus_loop_add_timeout (timeout, server_timeout_callback, context, NULL);
80 }
81
82 static void
83 remove_server_timeout (DBusTimeout *timeout,
84                        BusContext  *context)
85 {
86   bus_loop_remove_timeout (timeout, server_timeout_callback, context);
87 }
88
89 static void
90 new_connection_callback (DBusServer     *server,
91                          DBusConnection *new_connection,
92                          void           *data)
93 {
94   BusContext *context = data;
95   
96   if (!bus_connections_setup_connection (context->connections, new_connection))
97     {
98       _dbus_verbose ("No memory to setup new connection\n");
99
100       /* if we don't do this, it will get unref'd without
101        * being disconnected... kind of strange really
102        * that we have to do this, people won't get it right
103        * in general.
104        */
105       dbus_connection_disconnect (new_connection);
106     }
107   
108   /* on OOM, we won't have ref'd the connection so it will die. */
109 }
110
111 BusContext*
112 bus_context_new (const char  *address,
113                  const char **service_dirs,
114                  DBusError   *error)
115 {
116   BusContext *context;
117   DBusResultCode result;
118   
119   context = dbus_new0 (BusContext, 1);
120   if (context == NULL)
121     {
122       BUS_SET_OOM (error);
123       return NULL;
124     }
125   
126   context->refcount = 1;
127
128   context->address = _dbus_strdup (address);
129   if (context->address == NULL)
130     {
131       BUS_SET_OOM (error);
132       goto failed;
133     }
134   
135   context->server = dbus_server_listen (address, &result);
136   if (context->server == NULL)
137     {
138       dbus_set_error (error, DBUS_ERROR_FAILED,
139                       "Failed to start server on %s: %s\n",
140                       address, dbus_result_to_string (result));
141       goto failed;
142     }
143
144   context->activation = bus_activation_new (address, service_dirs,
145                                             error);
146   if (context->activation == NULL)
147     {
148       _DBUS_ASSERT_ERROR_IS_SET (error);
149       goto failed;
150     }
151
152   context->connections = bus_connections_new (context);
153   if (context->connections == NULL)
154     {
155       BUS_SET_OOM (error);
156       goto failed;
157     }
158
159   context->registry = bus_registry_new ();
160   if (context->registry == NULL)
161     {
162       BUS_SET_OOM (error);
163       goto failed;
164     }
165   
166   dbus_server_set_new_connection_function (context->server,
167                                            new_connection_callback,
168                                            context, NULL);
169   
170   if (!dbus_server_set_watch_functions (context->server,
171                                         (DBusAddWatchFunction) add_server_watch,
172                                         (DBusRemoveWatchFunction) remove_server_watch,
173                                         NULL,
174                                         context,
175                                         NULL))
176     {
177       BUS_SET_OOM (error);
178       goto failed;
179     }
180
181   if (!dbus_server_set_timeout_functions (context->server,
182                                           (DBusAddTimeoutFunction) add_server_timeout,
183                                           (DBusRemoveTimeoutFunction) remove_server_timeout,
184                                           NULL,
185                                           context, NULL))
186     {
187       BUS_SET_OOM (error);
188       goto failed;
189     }
190   
191   return context;
192   
193  failed:
194   bus_context_unref (context);
195   return NULL;
196 }
197
198 void
199 bus_context_shutdown (BusContext  *context)
200 {
201   if (context->server == NULL ||
202       !dbus_server_get_is_connected (context->server))
203     return;
204   
205   if (!dbus_server_set_watch_functions (context->server,
206                                         NULL, NULL, NULL,
207                                         context,
208                                         NULL))
209     _dbus_assert_not_reached ("setting watch functions to NULL failed");
210   
211   if (!dbus_server_set_timeout_functions (context->server,
212                                           NULL, NULL, NULL,
213                                           context,
214                                           NULL))
215     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
216   
217   dbus_server_disconnect (context->server);
218 }
219
220 void
221 bus_context_ref (BusContext *context)
222 {
223   _dbus_assert (context->refcount > 0);
224   context->refcount += 1;
225 }
226
227 void
228 bus_context_unref (BusContext *context)
229 {
230   _dbus_assert (context->refcount > 0);
231   context->refcount -= 1;
232
233   if (context->refcount == 0)
234     {
235       _dbus_verbose ("Finalizing bus context %p\n", context);
236       
237       bus_context_shutdown (context);
238
239       if (context->connections)
240         {
241           bus_connections_unref (context->connections);
242           context->connections = NULL;
243         }
244       
245       if (context->registry)
246         {
247           bus_registry_unref (context->registry);
248           context->registry = NULL;
249         }
250       
251       if (context->activation)
252         {
253           bus_activation_unref (context->activation);
254           context->activation = NULL;
255         }
256       
257       if (context->server)
258         {
259           dbus_server_unref (context->server);
260           context->server = NULL;
261         }
262       
263       dbus_free (context->address);
264       dbus_free (context);
265     }
266 }
267
268 BusRegistry*
269 bus_context_get_registry (BusContext  *context)
270 {
271   return context->registry;
272 }
273
274 BusConnections*
275 bus_context_get_connections (BusContext  *context)
276 {
277   return context->connections;
278 }
279
280 BusActivation*
281 bus_context_get_activation (BusContext  *context)
282 {
283   return context->activation;
284 }