2003-02-13 Anders Carlsson <andersca@codefactory.se>
[platform/upstream/dbus.git] / bus / connection.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* connection.c  Client connections
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 #include "connection.h"
24 #include "dispatch.h"
25 #include "loop.h"
26 #include "services.h"
27 #include <dbus/dbus-list.h>
28
29 static int connection_data_slot;
30 static DBusList *connections = NULL;
31
32 typedef struct
33 {
34   DBusList *services_owned;
35
36   char *name;
37 } BusConnectionData;
38
39 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
40
41 static void
42 connection_disconnect_handler (DBusConnection *connection,
43                                void           *data)
44 {
45   BusConnectionData *d;
46   BusService *service;
47
48   _dbus_warn ("Disconnected\n");
49
50   d = BUS_CONNECTION_DATA (connection);
51   _dbus_assert (d != NULL);  
52
53   /* Drop any service ownership */
54   while ((service = _dbus_list_get_last (&d->services_owned)))
55     bus_service_remove_owner (service, connection);
56
57   bus_dispatch_remove_connection (connection);
58   
59   /* no more watching */
60   dbus_connection_set_watch_functions (connection,
61                                        NULL, NULL,
62                                        connection,
63                                        NULL);
64   
65   dbus_connection_set_data (connection,
66                             connection_data_slot,
67                             NULL, NULL);
68   
69   _dbus_list_remove (&connections, connection);    
70   dbus_connection_unref (connection);
71 }
72
73 static void
74 connection_watch_callback (DBusWatch     *watch,
75                            unsigned int   condition,
76                            void          *data)
77 {
78   DBusConnection *connection = data;
79
80   dbus_connection_ref (connection);
81   
82   dbus_connection_handle_watch (connection, watch, condition);
83
84   while (dbus_connection_dispatch_message (connection));
85   dbus_connection_unref (connection);
86 }
87
88 static void
89 add_connection_watch (DBusWatch      *watch,
90                       DBusConnection *connection)
91 {
92   bus_loop_add_watch (watch, connection_watch_callback, connection,
93                       NULL);
94 }
95
96 static void
97 remove_connection_watch (DBusWatch      *watch,
98                          DBusConnection *connection)
99 {
100   bus_loop_remove_watch (watch, connection_watch_callback, connection);
101 }
102
103 static void
104 free_connection_data (void *data)
105 {
106   BusConnectionData *d = data;
107
108   /* services_owned should be NULL since we should be disconnected */
109   _dbus_assert (d->services_owned == NULL);
110
111   dbus_free (d->name);
112   
113   dbus_free (d);
114 }
115
116 dbus_bool_t
117 bus_connection_init (void)
118 {
119   connection_data_slot = dbus_connection_allocate_data_slot ();
120
121   if (connection_data_slot < 0)
122     return FALSE;
123
124   return TRUE;
125 }
126
127 dbus_bool_t
128 bus_connection_setup (DBusConnection *connection)
129 {
130   BusConnectionData *d;
131
132   d = dbus_new0 (BusConnectionData, 1);
133   
134   if (d == NULL)
135     return FALSE;
136   
137   if (!dbus_connection_set_data (connection,
138                                  connection_data_slot,
139                                  d, free_connection_data))
140     {
141       dbus_free (d);
142       return FALSE;
143     }
144   
145   if (!_dbus_list_append (&connections, connection))
146     {
147       /* this will free our data when connection gets finalized */
148       dbus_connection_disconnect (connection);
149       return FALSE;
150     }
151
152   dbus_connection_ref (connection);
153   
154   dbus_connection_set_watch_functions (connection,
155                                        (DBusAddWatchFunction) add_connection_watch,
156                                        (DBusRemoveWatchFunction) remove_connection_watch,
157                                        connection,
158                                        NULL);
159   
160   dbus_connection_set_disconnect_function (connection,
161                                            connection_disconnect_handler,
162                                            NULL, NULL);
163
164   /* Setup the connection with the dispatcher */
165   if (!bus_dispatch_add_connection (connection))
166     return FALSE;
167   
168   return TRUE;
169 }
170
171 dbus_bool_t
172 bus_connection_add_owned_service (DBusConnection *connection,
173                                   BusService     *service)
174 {
175   BusConnectionData *d;
176
177   d = BUS_CONNECTION_DATA (connection);
178   _dbus_assert (d != NULL);
179
180   if (!_dbus_list_append (&d->services_owned,
181                           service))
182     return FALSE;
183
184   return TRUE;
185 }
186
187 void
188 bus_connection_remove_owned_service (DBusConnection *connection,
189                                      BusService     *service)
190 {
191   BusConnectionData *d;
192
193   d = BUS_CONNECTION_DATA (connection);
194   _dbus_assert (d != NULL);
195
196   _dbus_list_remove_last (&d->services_owned, service);
197 }
198
199 dbus_bool_t
200 bus_connection_set_name (DBusConnection   *connection,
201                          const DBusString *name)
202 {
203   const char *c_name;
204   BusConnectionData *d;
205   
206   d = BUS_CONNECTION_DATA (connection);
207   _dbus_assert (d != NULL);
208   _dbus_assert (d->name == NULL);
209
210   _dbus_string_get_const_data (name, &c_name);
211
212   d->name = _dbus_strdup (c_name);
213
214   if (d->name == NULL)
215     return FALSE;
216
217   return TRUE;
218 }
219
220 const char *
221 bus_connection_get_name (DBusConnection *connection)
222 {
223   BusConnectionData *d;
224   
225   d = BUS_CONNECTION_DATA (connection);
226   _dbus_assert (d != NULL);
227   
228   return d->name;
229 }
230
231 void
232 bus_connection_foreach (BusConnectionForeachFunction  function,
233                         void                         *data)
234 {
235   _dbus_list_foreach (&connections, (DBusForeachFunction)function, data);
236 }