41c98c962772d0c5cebddbf8e9e515a004b270fb
[platform/upstream/dbus.git] / bus / driver.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* driver.c  Bus client (driver)
3  *
4  * Copyright (C) 2003  CodeFactory AB
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 "connection.h"
25 #include "driver.h"
26 #include "services.h"
27 #include <dbus/dbus-internals.h>
28 #include <dbus/dbus-string.h>
29 #include <string.h>
30
31 #define BUS_DRIVER_SERVICE_NAME "org.freedesktop.DBus"
32 #define BUS_DRIVER_HELLO_NAME "org.freedesktop.DBus.Hello"
33 #define BUS_DRIVER_WELCOME_NAME "org.freedesktop.DBus.Welcome"
34
35 static dbus_bool_t  bus_driver_send_welcome_message (DBusConnection *connection,
36                                                      DBusMessage    *hello_message);
37
38 static dbus_bool_t
39 create_unique_client_name (const char *name,
40                            DBusString *str)
41 {
42   /* We never want to use the same unique client name twice, because
43    * we want to guarantee that if you send a message to a given unique
44    * name, you always get the same application. So we use two numbers
45    * for INT_MAX * INT_MAX combinations, should be pretty safe against
46    * wraparound.
47    */
48   static int next_major_number = 0;
49   static int next_minor_number = 0;
50   int len;
51
52   if (!_dbus_string_append (str, name))
53     return FALSE;
54   
55   len = _dbus_string_get_length (str);
56   
57   while (TRUE)
58     {
59       /* start out with 1-0, go to 1-1, 1-2, 1-3,
60        * up to 1-MAXINT, then 2-0, 2-1, etc.
61        */
62       if (next_minor_number <= 0)
63         {
64           next_major_number += 1;
65           next_minor_number = 0;
66           if (next_major_number <= 0)
67             _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
68         }
69
70       _dbus_assert (next_major_number > 0);
71       _dbus_assert (next_minor_number >= 0);
72
73       /* appname:MAJOR-MINOR */
74       
75       if (!_dbus_string_append (str, ":"))
76         return FALSE;
77       
78       if (!_dbus_string_append_int (str, next_major_number))
79         return FALSE;
80
81       if (!_dbus_string_append (str, "-"))
82         return FALSE;
83       
84       if (!_dbus_string_append_int (str, next_minor_number))
85         return FALSE;
86
87       next_minor_number += 1;
88       
89       /* Check if a client with the name exists */
90       if (bus_service_lookup (str, FALSE) == NULL)
91         break;
92
93       /* drop the number again, try the next one. */
94       _dbus_string_set_length (str, len);
95     }
96
97   return TRUE;
98 }
99
100 static dbus_bool_t
101 bus_driver_handle_hello_message (DBusConnection *connection,
102                                  DBusMessage    *message)
103 {
104   DBusResultCode result;
105   char *name;
106   DBusString unique_name;
107   BusService *service;
108   dbus_bool_t retval;
109   
110   result = dbus_message_get_fields (message,
111                                     DBUS_TYPE_STRING, &name,
112                                     0);
113
114   /* FIXME: Handle this in a better way */
115   if (result != DBUS_RESULT_SUCCESS)
116     return FALSE;
117
118   if (!_dbus_string_init (&unique_name, _DBUS_INT_MAX))
119     return FALSE;
120   
121   if (!create_unique_client_name (name, &unique_name))
122     {
123       _dbus_string_free (&unique_name);
124       return FALSE;
125     }
126
127   /* Create the service */
128   service = bus_service_lookup (&unique_name, TRUE);
129   if (!service)
130     {
131       _dbus_string_free (&unique_name);
132       return FALSE;
133     }
134
135   /* FIXME: Error checks from this point */
136   
137   /* Add the connection as the owner */
138   bus_service_add_owner (service, connection);
139   bus_connection_set_name (connection, &unique_name);
140
141   /* We need to assign the sender to the message here */
142   _dbus_message_set_sender (message,
143                             bus_connection_get_name (connection));
144   
145   _dbus_string_free (&unique_name);
146
147   retval = bus_driver_send_welcome_message (connection, message);
148
149   return retval;
150 }
151
152 static dbus_bool_t
153 bus_driver_send_welcome_message (DBusConnection *connection,
154                                  DBusMessage    *hello_message)
155 {
156   DBusMessage *welcome;
157   const char *name;
158   dbus_bool_t retval;
159   
160   
161   name = bus_connection_get_name (connection);
162   _dbus_assert (name != NULL);
163   
164   welcome = dbus_message_new_reply (BUS_DRIVER_WELCOME_NAME,
165                                     hello_message);
166   if (welcome == NULL)
167     return FALSE;
168
169   /* FIXME: Return value */
170   _dbus_message_set_sender (welcome, BUS_DRIVER_SERVICE_NAME);
171   
172   if (!dbus_message_append_fields (welcome,
173                                    DBUS_TYPE_STRING, name,
174                                    NULL))
175     {
176       dbus_message_unref (welcome);
177       return FALSE;
178     }
179
180   retval = dbus_connection_send_message (connection, welcome, NULL, NULL);
181   dbus_message_unref (welcome);
182
183   return retval;
184 }
185
186 /* This is where all the magic occurs */
187 static DBusHandlerResult
188 bus_driver_message_handler (DBusMessageHandler *handler,
189                             DBusConnection     *connection,
190                             DBusMessage        *message,
191                             void               *user_data)
192 {
193   const char *service, *name;
194
195   service = dbus_message_get_service (message);
196   name = dbus_message_get_name (message);
197
198   _dbus_message_set_sender (message,
199                             bus_connection_get_name (connection));
200   
201   if (strcmp (service, BUS_DRIVER_SERVICE_NAME) == 0)
202     {
203       if (strcmp (name, BUS_DRIVER_HELLO_NAME) == 0)
204         bus_driver_handle_hello_message (connection, message);
205     }
206   else
207     {
208       /* FIXME: Dispatch the message :-) */
209     }
210
211   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
212 }
213
214 dbus_bool_t
215 bus_driver_add_connection (DBusConnection *connection)
216 {
217   DBusMessageHandler *handler;
218
219   handler = dbus_message_handler_new (bus_driver_message_handler, NULL, NULL);
220
221   if (!dbus_connection_add_filter (connection, handler))
222     {
223       dbus_message_handler_unref (handler);
224
225       return FALSE;
226     }
227
228   /* FIXME we are leaking the DBusMessageHandler */
229   
230   _dbus_verbose ("D-Bus driver on board...\n");
231   
232   return TRUE;
233 }
234
235 void
236 bus_driver_remove_connection (DBusConnection *connection)
237 {
238   BusService *service;
239   DBusString service_name;
240   const char *name;
241
242   name = bus_connection_get_name (connection);
243
244   if (name == NULL)
245     return;
246   
247   _dbus_string_init_const (&service_name, name);
248   
249   service = bus_service_lookup (&service_name, FALSE);
250
251   if (service)
252     bus_service_free (service);
253 }