bus.c revision ce173b29fc1e9432cb5956952afdbe775da12415
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
32struct BusContext
33{
34  int refcount;
35  char *address;
36  DBusServer *server;
37  BusConnections *connections;
38  BusActivation *activation;
39  BusRegistry *registry;
40};
41
42static void
43server_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
52static dbus_bool_t
53add_server_watch (DBusWatch  *watch,
54                  BusContext *context)
55{
56  return bus_loop_add_watch (watch, server_watch_callback, context,
57                             NULL);
58}
59
60static void
61remove_server_watch (DBusWatch  *watch,
62                     BusContext *context)
63{
64  bus_loop_remove_watch (watch, server_watch_callback, context);
65}
66
67
68static void
69server_timeout_callback (DBusTimeout   *timeout,
70                         void          *data)
71{
72  dbus_timeout_handle (timeout);
73}
74
75static dbus_bool_t
76add_server_timeout (DBusTimeout *timeout,
77                    BusContext  *context)
78{
79  return bus_loop_add_timeout (timeout, server_timeout_callback, context, NULL);
80}
81
82static void
83remove_server_timeout (DBusTimeout *timeout,
84                       BusContext  *context)
85{
86  bus_loop_remove_timeout (timeout, server_timeout_callback, context);
87}
88
89static void
90new_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
111BusContext*
112bus_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
198void
199bus_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
220void
221bus_context_ref (BusContext *context)
222{
223  _dbus_assert (context->refcount > 0);
224  context->refcount += 1;
225}
226
227void
228bus_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
268BusRegistry*
269bus_context_get_registry (BusContext  *context)
270{
271  return context->registry;
272}
273
274BusConnections*
275bus_context_get_connections (BusContext  *context)
276{
277  return context->connections;
278}
279
280BusActivation*
281bus_context_get_activation (BusContext  *context)
282{
283  return context->activation;
284}
285