2003-01-05 Havoc Pennington <hp@pobox.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 "loop.h"
25 #include "services.h"
26 #include <dbus/dbus-list.h>
27
28 static int connection_data_slot;
29 static DBusList *connections = NULL;
30
31 typedef struct
32 {
33   DBusList *services_owned;
34
35 } BusConnectionData;
36
37 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
38
39 static void
40 connection_error_handler (DBusConnection *connection,
41                           DBusResultCode  error_code,
42                           void           *data)
43 {
44   BusConnectionData *d;
45   BusService *service;
46   
47   _dbus_warn ("Error on connection: %s\n",
48               dbus_result_to_string (error_code));
49
50   d = BUS_CONNECTION_DATA (connection);
51   _dbus_assert (d != NULL);
52   
53   /* we don't want to be called again since we're dropping the connection */
54   dbus_connection_set_error_function (connection, NULL, NULL, NULL);
55
56   /* Drop any service ownership */
57   while ((service = _dbus_list_get_last (&d->services_owned)))
58     bus_service_remove_owner (service, connection);
59
60   /* no more watching */
61   dbus_connection_set_watch_functions (connection,
62                                        NULL, NULL,
63                                        connection,
64                                        NULL);
65   
66   dbus_connection_set_data (connection,
67                             connection_data_slot,
68                             NULL, NULL);
69   
70   _dbus_list_remove (&connections, connection);    
71   dbus_connection_unref (connection);
72 }
73
74 static void
75 connection_watch_callback (DBusWatch     *watch,
76                            unsigned int   condition,
77                            void          *data)
78 {
79   DBusConnection *connection = data;
80
81   dbus_connection_handle_watch (connection, watch, condition);
82 }
83
84 static void
85 add_connection_watch (DBusWatch      *watch,
86                       DBusConnection *connection)
87 {
88   bus_loop_add_watch (watch, connection_watch_callback, connection,
89                       NULL);
90 }
91
92 static void
93 remove_connection_watch (DBusWatch      *watch,
94                          DBusConnection *connection)
95 {
96   bus_loop_remove_watch (watch, connection_watch_callback, connection);
97 }
98
99 static void
100 free_connection_data (void *data)
101 {
102   BusConnectionData *d = data;
103
104   /* services_owned should be NULL since we should be disconnected */
105   _dbus_assert (d->services_owned == NULL);
106   
107   dbus_free (d);
108 }
109
110 dbus_bool_t
111 bus_connection_init (void)
112 {
113   connection_data_slot = dbus_connection_allocate_data_slot ();
114
115   if (connection_data_slot < 0)
116     return FALSE;
117
118   return TRUE;
119 }
120
121 dbus_bool_t
122 bus_connection_setup (DBusConnection *connection)
123 {
124   BusConnectionData *d;
125
126   d = dbus_new (BusConnectionData, 1);
127   if (d == NULL)
128     return FALSE;
129   
130   if (!dbus_connection_set_data (connection,
131                                  connection_data_slot,
132                                  d, free_connection_data))
133     {
134       dbus_free (d);
135       return FALSE;
136     }
137   
138   if (!_dbus_list_append (&connections, connection))
139     {
140       /* this will free our data when connection gets finalized */
141       dbus_connection_disconnect (connection);
142       return FALSE;
143     }
144
145   dbus_connection_ref (connection);
146   
147   dbus_connection_set_watch_functions (connection,
148                                        (DBusAddWatchFunction) add_connection_watch,
149                                        (DBusRemoveWatchFunction) remove_connection_watch,
150                                        connection,
151                                        NULL);
152   
153   dbus_connection_set_error_function (connection,
154                                       connection_error_handler,
155                                       NULL, NULL);
156
157   return TRUE;
158 }
159
160 dbus_bool_t
161 bus_connection_add_owned_service (DBusConnection *connection,
162                                   BusService     *service)
163 {
164   BusConnectionData *d;
165
166   d = BUS_CONNECTION_DATA (connection);
167   _dbus_assert (d != NULL);
168
169   if (!_dbus_list_append (&d->services_owned,
170                           service))
171     return FALSE;
172
173   return TRUE;
174 }
175
176 void
177 bus_connection_remove_owned_service (DBusConnection *connection,
178                                      BusService     *service)
179 {
180   BusConnectionData *d;
181
182   d = BUS_CONNECTION_DATA (connection);
183   _dbus_assert (d != NULL);
184
185   _dbus_list_remove_last (&d->services_owned, service);
186 }