2003-02-16 Anders Carlsson <andersca@codefactory.se>
[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 "activation.h"
25 #include "connection.h"
26 #include "driver.h"
27 #include "dispatch.h"
28 #include "services.h"
29 #include "utils.h"
30 #include <dbus/dbus-string.h>
31 #include <dbus/dbus-internals.h>
32 #include <string.h>
33
34 static void bus_driver_send_welcome_message (DBusConnection *connection,
35                                              DBusMessage    *hello_message);
36
37 void
38 bus_driver_send_service_deleted (const char *service_name)
39 {
40   DBusMessage *message;
41
42   _dbus_verbose ("sending service deleted: %s\n", service_name);
43   
44   BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST,
45                                               DBUS_MESSAGE_SERVICE_DELETED));
46   
47   BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS));
48
49   BUS_HANDLE_OOM (dbus_message_append_args (message,
50                                             DBUS_TYPE_STRING, service_name,
51                                             0));
52   bus_dispatch_broadcast_message (message);
53   dbus_message_unref (message);  
54 }
55
56 void
57 bus_driver_send_service_created (const char *service_name)
58 {
59   DBusMessage *message;
60
61   BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST,
62                                               DBUS_MESSAGE_SERVICE_CREATED));
63   
64   BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS));
65   
66   BUS_HANDLE_OOM (dbus_message_append_args (message,
67                                             DBUS_TYPE_STRING, service_name,
68                                             0));
69   bus_dispatch_broadcast_message (message);
70   dbus_message_unref (message);
71 }
72
73 void
74 bus_driver_send_service_lost (DBusConnection *connection,
75                               const char *service_name)
76 {
77   DBusMessage *message;
78
79   BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST,
80                                               DBUS_MESSAGE_SERVICE_LOST));
81   
82   BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS));
83   BUS_HANDLE_OOM (dbus_message_append_args (message,
84                                             DBUS_TYPE_STRING, service_name,
85                                             0));
86   BUS_HANDLE_OOM (dbus_connection_send_message (connection, message, NULL, NULL));
87   
88   dbus_message_unref (message);
89 }
90
91 void
92 bus_driver_send_service_acquired (DBusConnection *connection,
93                                   const char *service_name)
94 {
95   DBusMessage *message;
96
97   BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST,
98                                               DBUS_MESSAGE_SERVICE_ACQUIRED));
99   
100   BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS));
101   BUS_HANDLE_OOM (dbus_message_append_args (message,
102                                             DBUS_TYPE_STRING, service_name,
103                                             0));
104   BUS_HANDLE_OOM (dbus_connection_send_message (connection, message, NULL, NULL));
105   
106   dbus_message_unref (message);
107 }
108
109 static dbus_bool_t
110 create_unique_client_name (DBusString *str)
111 {
112   /* We never want to use the same unique client name twice, because
113    * we want to guarantee that if you send a message to a given unique
114    * name, you always get the same application. So we use two numbers
115    * for INT_MAX * INT_MAX combinations, should be pretty safe against
116    * wraparound.
117    */
118   static int next_major_number = 0;
119   static int next_minor_number = 0;
120   int len;
121
122   len = _dbus_string_get_length (str);
123   
124   while (TRUE)
125     {
126       /* start out with 1-0, go to 1-1, 1-2, 1-3,
127        * up to 1-MAXINT, then 2-0, 2-1, etc.
128        */
129       if (next_minor_number <= 0)
130         {
131           next_major_number += 1;
132           next_minor_number = 0;
133           if (next_major_number <= 0)
134             _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
135         }
136
137       _dbus_assert (next_major_number > 0);
138       _dbus_assert (next_minor_number >= 0);
139
140       /* appname:MAJOR-MINOR */
141       
142       if (!_dbus_string_append (str, ":"))
143         return FALSE;
144       
145       if (!_dbus_string_append_int (str, next_major_number))
146         return FALSE;
147
148       if (!_dbus_string_append (str, "-"))
149         return FALSE;
150       
151       if (!_dbus_string_append_int (str, next_minor_number))
152         return FALSE;
153
154       next_minor_number += 1;
155       
156       /* Check if a client with the name exists */
157       if (bus_service_lookup (str, FALSE) == NULL)
158         break;
159
160       /* drop the number again, try the next one. */
161       _dbus_string_set_length (str, len);
162     }
163
164   return TRUE;
165 }
166
167 static void
168 bus_driver_handle_hello (DBusConnection *connection,
169                          DBusMessage    *message)
170 {
171   DBusString unique_name;
172   BusService *service;
173
174   BUS_HANDLE_OOM (_dbus_string_init (&unique_name, _DBUS_INT_MAX));
175   BUS_HANDLE_OOM (create_unique_client_name (&unique_name));
176
177   BUS_HANDLE_OOM (bus_connection_set_name (connection, &unique_name));
178   BUS_HANDLE_OOM (dbus_message_set_sender (message,
179                                            bus_connection_get_name (connection)));
180   
181   BUS_HANDLE_OOM (bus_driver_send_welcome_message (connection, message));
182
183   /* Create the service */
184   BUS_HANDLE_OOM (service = bus_service_lookup (&unique_name, TRUE));
185   bus_service_set_prohibit_replacement (service, TRUE);
186   
187   /* Add the connection as the owner */
188   BUS_HANDLE_OOM (bus_service_add_owner (service, connection));
189
190   _dbus_string_free (&unique_name);
191 }
192
193 static void
194 bus_driver_send_welcome_message (DBusConnection *connection,
195                                  DBusMessage    *hello_message)
196 {
197   DBusMessage *welcome;
198   const char *name;
199   
200   name = bus_connection_get_name (connection);
201   _dbus_assert (name != NULL);
202   
203   BUS_HANDLE_OOM (welcome = dbus_message_new_reply (hello_message));
204   
205   BUS_HANDLE_OOM (dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS));
206   
207   BUS_HANDLE_OOM (dbus_message_append_args (welcome,
208                                             DBUS_TYPE_STRING, name,
209                                             NULL));
210   
211   BUS_HANDLE_OOM (dbus_connection_send_message (connection, welcome, NULL, NULL));
212   
213   dbus_message_unref (welcome);
214 }
215
216 static void
217 bus_driver_handle_list_services (DBusConnection *connection,
218                                  DBusMessage    *message)
219 {
220   DBusMessage *reply;
221   int len, i;
222   char **services;
223
224   BUS_HANDLE_OOM (reply = dbus_message_new_reply (message));
225
226   BUS_HANDLE_OOM (services = bus_services_list (&len));
227
228   BUS_HANDLE_OOM (dbus_message_append_args (reply,
229                                             DBUS_TYPE_STRING_ARRAY, services, len,
230                                             0));
231
232   BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL));
233
234   dbus_message_unref (reply);
235
236   if (services != NULL)
237     {
238       for (i = 0; i < len; i++)
239         dbus_free (services[i]);
240       dbus_free (services);
241     }
242 }
243
244 static void
245 bus_driver_handle_acquire_service (DBusConnection *connection,
246                                    DBusMessage    *message)
247 {
248   DBusMessage *reply;
249   DBusResultCode result;
250   DBusString service_name;
251   BusService *service;  
252   char *name;
253   int service_reply;
254   int flags;
255   
256   BUS_HANDLE_OOM ((result = dbus_message_get_args (message,
257                                                    DBUS_TYPE_STRING, &name,
258                                                    DBUS_TYPE_UINT32, &flags,
259                                                    0)) != DBUS_RESULT_NO_MEMORY);
260   
261   if (result != DBUS_RESULT_SUCCESS)
262     {
263       dbus_free (name);
264       dbus_connection_disconnect (connection);
265       return;
266     }
267
268   _dbus_verbose ("Trying to own service %s with flags %d\n", name, flags);
269
270   _dbus_string_init_const (&service_name, name);
271   service = bus_service_lookup (&service_name, TRUE);
272
273   BUS_HANDLE_OOM ((reply = dbus_message_new_reply (message)));
274   
275   /*
276    * Check if the service already has an owner
277    */
278   if (bus_service_get_primary_owner (service) != NULL)
279     {
280       if (bus_service_has_owner (service, connection))
281         service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER;
282       else if (!(flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING))
283         service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS;
284       else
285         {
286           if (bus_service_get_prohibit_replacement (service))
287             {
288               
289               /* Queue the connection */
290               BUS_HANDLE_OOM (bus_service_add_owner (service, connection));
291               
292               service_reply = DBUS_SERVICE_REPLY_IN_QUEUE;
293             }
294           else
295             {
296               DBusConnection *owner;
297               
298               /* We can replace the primary owner */
299               owner = bus_service_get_primary_owner (service);
300
301               /* We enqueue the new owner and remove the first one because
302                * that will cause ServiceAcquired and ServiceLost messages to
303                * be sent.
304                */
305               BUS_HANDLE_OOM (bus_service_add_owner (service, connection));
306               bus_service_remove_owner (service, owner);
307               _dbus_assert (connection == bus_service_get_primary_owner (service));
308               service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
309             }
310         }
311     }
312   else
313     {
314       bus_service_set_prohibit_replacement (service,
315                                             (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT));
316       
317       /* Broadcast service created message */
318       bus_driver_send_service_created (bus_service_get_name (service));
319       
320       BUS_HANDLE_OOM (bus_service_add_owner (service, connection));
321                         
322       service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
323     }
324
325   BUS_HANDLE_OOM (dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0));
326
327   /* Send service reply */
328   BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL));
329   dbus_free (name);
330   dbus_message_unref (reply);
331 }
332
333 static void
334 bus_driver_handle_service_exists (DBusConnection *connection,
335                                   DBusMessage    *message)
336 {
337   DBusMessage *reply;
338   DBusResultCode result;
339   DBusString service_name;
340   BusService *service;
341   char *name;
342   
343   BUS_HANDLE_OOM ((result = dbus_message_get_args (message,
344                                                    DBUS_TYPE_STRING, &name,
345                                                    0)) != DBUS_RESULT_NO_MEMORY);
346   if (result != DBUS_RESULT_SUCCESS)
347     {
348       dbus_free (name);
349       dbus_connection_disconnect (connection);
350       return;
351     }
352
353   _dbus_string_init_const (&service_name, name);
354   service = bus_service_lookup (&service_name, FALSE);
355  
356   BUS_HANDLE_OOM ((reply = dbus_message_new_reply (message)));
357   BUS_HANDLE_OOM (dbus_message_set_sender (reply, DBUS_SERVICE_DBUS));
358
359   BUS_HANDLE_OOM (dbus_message_append_args (reply,
360                                             DBUS_TYPE_UINT32, service != NULL,
361                                             0));
362   BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL));
363   dbus_message_unref (reply);
364   dbus_free (name);
365 }
366
367 static void
368 bus_driver_handle_activate_service (DBusConnection *connection,
369                                     DBusMessage    *message)
370 {
371   DBusResultCode result;
372   dbus_uint32_t flags;
373   char *name;
374   DBusError error;
375   
376   BUS_HANDLE_OOM ((result = dbus_message_get_args (message,
377                                                    DBUS_TYPE_STRING, &name,
378                                                    DBUS_TYPE_UINT32, &flags,
379                                                    0)) != DBUS_RESULT_NO_MEMORY);
380   if (result != DBUS_RESULT_SUCCESS)
381     {
382       dbus_free (name);
383       dbus_connection_disconnect (connection);
384       return;
385     }
386
387   if (!bus_activation_activate_service (name, &error))
388     {
389       DBusMessage *error_reply;
390       
391       BUS_HANDLE_OOM (error_reply = dbus_message_new_error_reply (message,
392                                                                   error.name, error.message));
393       dbus_error_free (&error);
394
395       BUS_HANDLE_OOM (dbus_connection_send_message (connection, error_reply, NULL, NULL));
396       dbus_message_unref (error_reply);
397     }
398 }
399
400 void
401 bus_driver_handle_message (DBusConnection *connection,
402                            DBusMessage    *message)
403 {
404   const char *name, *sender;
405
406   _dbus_verbose ("Driver got a message: %s\n",
407                  dbus_message_get_name (message));
408   
409   name = dbus_message_get_name (message);
410   sender = dbus_message_get_sender (message);
411
412   if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0))
413     {
414       _dbus_verbose ("Trying to send a message without being registered. Disconnecting.\n");
415       dbus_connection_disconnect (connection);
416       return;
417     }
418
419   /* Now check names. */
420   if (strcmp (name, DBUS_MESSAGE_HELLO) == 0)
421     bus_driver_handle_hello (connection, message);
422   else if (strcmp (name, DBUS_MESSAGE_LIST_SERVICES) == 0)
423     bus_driver_handle_list_services (connection, message);
424   else if (strcmp (name, DBUS_MESSAGE_ACQUIRE_SERVICE) == 0)
425     bus_driver_handle_acquire_service (connection, message);
426   else if (strcmp (name, DBUS_MESSAGE_SERVICE_EXISTS) == 0)
427     bus_driver_handle_service_exists (connection, message);
428   else if (strcmp (name, DBUS_MESSAGE_ACTIVATE_SERVICE) == 0)
429     bus_driver_handle_activate_service (connection, message);
430 }
431
432 void
433 bus_driver_remove_connection (DBusConnection *connection)
434 {
435   /* Does nothing for now */
436 }