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