2003-04-13 Havoc Pennington <hp@pobox.com>
[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  * Copyright (C) 2003 Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "activation.h"
26 #include "connection.h"
27 #include "driver.h"
28 #include "dispatch.h"
29 #include "services.h"
30 #include "utils.h"
31 #include <dbus/dbus-string.h>
32 #include <dbus/dbus-internals.h>
33 #include <string.h>
34
35 static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
36                                                     DBusMessage    *hello_message,
37                                                     BusTransaction *transaction,
38                                                     DBusError      *error);
39
40 dbus_bool_t
41 bus_driver_send_service_deleted (const char     *service_name,
42                                  BusTransaction *transaction,
43                                  DBusError      *error)
44 {
45   DBusMessage *message;
46   dbus_bool_t retval;
47
48   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
49   
50   _dbus_verbose ("sending service deleted: %s\n", service_name);
51
52   message = dbus_message_new (DBUS_SERVICE_BROADCAST,
53                               DBUS_MESSAGE_SERVICE_DELETED);
54   if (message == NULL)
55     {
56       BUS_SET_OOM (error);
57       return FALSE;
58     }
59   
60   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
61       !dbus_message_append_args (message,
62                                  DBUS_TYPE_STRING, service_name,
63                                  0))
64     {
65       dbus_message_unref (message);
66       BUS_SET_OOM (error);
67       return FALSE;
68     }
69
70   retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
71   dbus_message_unref (message);
72
73   return retval;
74 }
75
76 dbus_bool_t
77 bus_driver_send_service_created (const char     *service_name,
78                                  BusTransaction *transaction,
79                                  DBusError      *error)
80 {
81   DBusMessage *message;
82   dbus_bool_t retval;
83
84   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
85   
86   message = dbus_message_new (DBUS_SERVICE_BROADCAST,
87                               DBUS_MESSAGE_SERVICE_CREATED);
88   if (message == NULL)
89     {
90       BUS_SET_OOM (error);
91       return FALSE;
92     }
93   
94   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
95     {
96       dbus_message_unref (message);
97       BUS_SET_OOM (error);
98       return FALSE;
99     }
100   
101   if (!dbus_message_append_args (message,
102                                  DBUS_TYPE_STRING, service_name,
103                                  0))
104     {
105       dbus_message_unref (message);
106       BUS_SET_OOM (error);
107       return FALSE;
108     }
109   
110   retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
111   dbus_message_unref (message);
112
113   return retval;
114 }
115
116 dbus_bool_t
117 bus_driver_send_service_lost (DBusConnection *connection,
118                               const char     *service_name,
119                               BusTransaction *transaction,
120                               DBusError      *error)
121 {
122   DBusMessage *message;
123
124   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
125   
126   message = dbus_message_new (bus_connection_get_name (connection),
127                               DBUS_MESSAGE_SERVICE_LOST);
128   if (message == NULL)
129     {
130       BUS_SET_OOM (error);
131       return FALSE;
132     }
133   
134   if (!dbus_message_append_args (message,
135                                  DBUS_TYPE_STRING, service_name,
136                                  0))
137     {
138       dbus_message_unref (message);
139       BUS_SET_OOM (error);
140       return FALSE;
141     }
142
143   if (!bus_transaction_send_from_driver (transaction, connection, message))
144     {
145       dbus_message_unref (message);
146       BUS_SET_OOM (error);
147       return FALSE;
148     }
149   else
150     {
151       dbus_message_unref (message);
152       return TRUE;
153     }
154 }
155
156 dbus_bool_t
157 bus_driver_send_service_acquired (DBusConnection *connection,
158                                   const char     *service_name,
159                                   BusTransaction *transaction,
160                                   DBusError      *error)
161 {
162   DBusMessage *message;
163
164   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
165   
166   message = dbus_message_new (bus_connection_get_name (connection),
167                               DBUS_MESSAGE_SERVICE_ACQUIRED);
168   if (message == NULL)
169     {
170       BUS_SET_OOM (error);
171       return FALSE;
172     }
173   
174   if (!dbus_message_append_args (message,
175                                  DBUS_TYPE_STRING, service_name,
176                                  0))
177     {
178       dbus_message_unref (message);
179       BUS_SET_OOM (error);
180       return FALSE;
181     }
182
183   if (!bus_transaction_send_from_driver (transaction, connection, message))
184     {
185       dbus_message_unref (message);
186       BUS_SET_OOM (error);
187       return FALSE;
188     }
189   else
190     {
191       dbus_message_unref (message);
192       return TRUE;
193     }
194 }
195
196 static dbus_bool_t
197 create_unique_client_name (BusRegistry *registry,
198                            DBusString  *str)
199 {
200   /* We never want to use the same unique client name twice, because
201    * we want to guarantee that if you send a message to a given unique
202    * name, you always get the same application. So we use two numbers
203    * for INT_MAX * INT_MAX combinations, should be pretty safe against
204    * wraparound.
205    */
206   static int next_major_number = 0;
207   static int next_minor_number = 0;
208   int len;
209
210   len = _dbus_string_get_length (str);
211   
212   while (TRUE)
213     {
214       /* start out with 1-0, go to 1-1, 1-2, 1-3,
215        * up to 1-MAXINT, then 2-0, 2-1, etc.
216        */
217       if (next_minor_number <= 0)
218         {
219           next_major_number += 1;
220           next_minor_number = 0;
221           if (next_major_number <= 0)
222             _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
223         }
224
225       _dbus_assert (next_major_number > 0);
226       _dbus_assert (next_minor_number >= 0);
227
228       /* appname:MAJOR-MINOR */
229       
230       if (!_dbus_string_append (str, ":"))
231         return FALSE;
232       
233       if (!_dbus_string_append_int (str, next_major_number))
234         return FALSE;
235
236       if (!_dbus_string_append (str, "-"))
237         return FALSE;
238       
239       if (!_dbus_string_append_int (str, next_minor_number))
240         return FALSE;
241
242       next_minor_number += 1;
243       
244       /* Check if a client with the name exists */
245       if (bus_registry_lookup (registry, str) == NULL)
246         break;
247
248       /* drop the number again, try the next one. */
249       _dbus_string_set_length (str, len);
250     }
251
252   return TRUE;
253 }
254
255 static dbus_bool_t
256 bus_driver_handle_hello (DBusConnection *connection,
257                          BusTransaction *transaction,
258                          DBusMessage    *message,
259                          DBusError      *error)
260 {
261   DBusString unique_name;
262   BusService *service;
263   dbus_bool_t retval;
264   BusRegistry *registry;
265
266   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
267   
268   if (!_dbus_string_init (&unique_name))
269     {
270       BUS_SET_OOM (error);
271       return FALSE;
272     }
273
274   retval = FALSE;
275
276   registry = bus_connection_get_registry (connection);
277   
278   if (!create_unique_client_name (registry, &unique_name))
279     {
280       BUS_SET_OOM (error);
281       goto out_0;
282     }
283
284   if (!bus_connection_set_name (connection, &unique_name))
285     {
286       BUS_SET_OOM (error);
287       goto out_0;
288     }
289   
290   if (!dbus_message_set_sender (message,
291                                 bus_connection_get_name (connection)))
292     {
293       BUS_SET_OOM (error);
294       goto out_0;
295     }
296   
297   if (!bus_driver_send_welcome_message (connection, message, transaction, error))
298     goto out_0;
299
300   /* Create the service */
301   service = bus_registry_ensure (registry,
302                                  &unique_name, connection, transaction, error);
303   if (service == NULL)
304     goto out_0;
305   
306   bus_service_set_prohibit_replacement (service, TRUE);
307
308   retval = TRUE;
309   
310  out_0:
311   _dbus_string_free (&unique_name);
312   return retval;
313 }
314
315 static dbus_bool_t
316 bus_driver_send_welcome_message (DBusConnection *connection,
317                                  DBusMessage    *hello_message,
318                                  BusTransaction *transaction,
319                                  DBusError      *error)
320 {
321   DBusMessage *welcome;
322   const char *name;
323
324   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
325   
326   name = bus_connection_get_name (connection);
327   _dbus_assert (name != NULL);
328   
329   welcome = dbus_message_new_reply (hello_message);
330   if (welcome == NULL)
331     {
332       BUS_SET_OOM (error);
333       return FALSE;
334     }
335   
336   if (!dbus_message_append_args (welcome,
337                                  DBUS_TYPE_STRING, name,
338                                  NULL))
339     {
340       dbus_message_unref (welcome);
341       BUS_SET_OOM (error);
342       return FALSE;
343     }
344
345   if (!bus_transaction_send_from_driver (transaction, connection, welcome))
346     {
347       dbus_message_unref (welcome);
348       BUS_SET_OOM (error);
349       return FALSE;
350     }
351   else
352     {
353       dbus_message_unref (welcome);
354       return TRUE;
355     }
356 }
357
358 static dbus_bool_t
359 bus_driver_handle_list_services (DBusConnection *connection,
360                                  BusTransaction *transaction,
361                                  DBusMessage    *message,
362                                  DBusError      *error)
363 {
364   DBusMessage *reply;
365   int len;
366   char **services;
367   BusRegistry *registry;
368
369   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
370   
371   registry = bus_connection_get_registry (connection);
372   
373   reply = dbus_message_new_reply (message);
374   if (reply == NULL)
375     {
376       BUS_SET_OOM (error);
377       return FALSE;
378     }
379
380   if (!bus_registry_list_services (registry, &services, &len))
381     {
382       dbus_message_unref (reply);
383       BUS_SET_OOM (error);
384       return FALSE;
385     }
386   
387   if (!dbus_message_append_args (reply,
388                                  DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, services, len,
389                                  0))
390     {
391       dbus_free_string_array (services);
392       dbus_message_unref (reply);
393       BUS_SET_OOM (error);
394       return FALSE;
395     }
396
397   dbus_free_string_array (services);
398   
399   if (!bus_transaction_send_from_driver (transaction, connection, reply))
400     {
401       dbus_message_unref (reply);
402       BUS_SET_OOM (error);
403       return FALSE;
404     }
405   else
406     {
407       dbus_message_unref (reply);
408       return TRUE;
409     }
410 }
411
412 static dbus_bool_t
413 bus_driver_handle_acquire_service (DBusConnection *connection,
414                                    BusTransaction *transaction,
415                                    DBusMessage    *message,
416                                    DBusError      *error)
417 {
418   DBusMessage *reply;
419   DBusString service_name;
420   char *name;
421   int service_reply;
422   int flags;
423   dbus_bool_t retval;
424   BusRegistry *registry;
425
426   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
427   
428   registry = bus_connection_get_registry (connection);
429   
430   if (!dbus_message_get_args (message, error,
431                               DBUS_TYPE_STRING, &name,
432                               DBUS_TYPE_UINT32, &flags,
433                               0))
434     return FALSE;
435   
436   _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags);
437   
438   retval = FALSE;
439   reply = NULL;
440
441   _dbus_string_init_const (&service_name, name);
442
443   if (!bus_registry_acquire_service (registry, connection,
444                                      &service_name, flags,
445                                      &service_reply, transaction,
446                                      error))
447     goto out;
448   
449   reply = dbus_message_new_reply (message);
450   if (reply == NULL)
451     {
452       BUS_SET_OOM (error);
453       goto out;
454     }
455
456   if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, DBUS_TYPE_INVALID))
457     {
458       BUS_SET_OOM (error);
459       goto out;
460     }
461
462   if (!bus_transaction_send_from_driver (transaction, connection, reply))
463     {
464       BUS_SET_OOM (error);
465       goto out;
466     }
467
468   retval = TRUE;
469   
470  out:
471   dbus_free (name);
472   if (reply)
473     dbus_message_unref (reply);
474   return retval;
475
476
477 static dbus_bool_t
478 bus_driver_handle_service_exists (DBusConnection *connection,
479                                   BusTransaction *transaction,
480                                   DBusMessage    *message,
481                                   DBusError      *error)
482 {
483   DBusMessage *reply;
484   DBusString service_name;
485   BusService *service;
486   char *name;
487   dbus_bool_t retval;
488   BusRegistry *registry;
489
490   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
491   
492   registry = bus_connection_get_registry (connection);
493   
494   if (!dbus_message_get_args (message, error,
495                               DBUS_TYPE_STRING, &name,
496                               0))
497     return FALSE;
498
499   retval = FALSE;
500   
501   _dbus_string_init_const (&service_name, name);
502   service = bus_registry_lookup (registry, &service_name);
503  
504   reply = dbus_message_new_reply (message);
505   if (reply == NULL)
506     {
507       BUS_SET_OOM (error);
508       goto out;
509     }
510
511   if (!dbus_message_append_args (reply,
512                                  DBUS_TYPE_UINT32, service != NULL,
513                                  0))
514     {
515       BUS_SET_OOM (error);
516       goto out;
517     }
518
519   if (!bus_transaction_send_from_driver (transaction, connection, reply))
520     {
521       BUS_SET_OOM (error);
522       goto out;
523     }
524
525   retval = TRUE;
526   
527  out:
528   if (reply)
529     dbus_message_unref (reply);
530   dbus_free (name);
531
532   return retval;
533 }
534
535 static dbus_bool_t
536 bus_driver_handle_activate_service (DBusConnection *connection,
537                                     BusTransaction *transaction,
538                                     DBusMessage    *message,
539                                     DBusError      *error)
540 {
541   dbus_uint32_t flags;
542   char *name;
543   dbus_bool_t retval;
544   BusActivation *activation;
545
546   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
547   
548   activation = bus_connection_get_activation (connection);
549   
550   if (!dbus_message_get_args (message, error,
551                               DBUS_TYPE_STRING, &name,
552                               DBUS_TYPE_UINT32, &flags,
553                               0))
554     {
555       _DBUS_ASSERT_ERROR_IS_SET (error);
556       _dbus_verbose ("No memory to get arguments to ActivateService\n");
557       return FALSE;
558     }
559
560   retval = FALSE;
561
562   if (!bus_activation_activate_service (activation, connection, transaction,
563                                         message, name, error))
564     {
565       _DBUS_ASSERT_ERROR_IS_SET (error);
566       _dbus_verbose ("bus_activation_activate_service() failed\n");
567       goto out;
568     }
569
570   retval = TRUE;
571   
572  out:
573   dbus_free (name);
574   return retval;
575 }
576
577 /* For speed it might be useful to sort this in order of
578  * frequency of use (but doesn't matter with only a few items
579  * anyhow)
580  */
581 struct
582 {
583   const char *name;
584   dbus_bool_t (* handler) (DBusConnection *connection,
585                            BusTransaction *transaction,
586                            DBusMessage    *message,
587                            DBusError      *error);
588 } message_handlers[] = {
589   { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
590   { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
591   { DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
592   { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
593   { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
594 };
595
596 dbus_bool_t
597 bus_driver_handle_message (DBusConnection *connection,
598                            BusTransaction *transaction,
599                            DBusMessage    *message,
600                            DBusError      *error)
601 {
602   const char *name, *sender;
603   int i;
604
605   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
606   
607   _dbus_verbose ("Driver got a message: %s\n",
608                  dbus_message_get_name (message));
609   
610   name = dbus_message_get_name (message);
611   sender = dbus_message_get_sender (message);
612
613   if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0))
614     {
615       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
616                       "Client tried to send a message other than %s without being registered",
617                       DBUS_MESSAGE_HELLO);
618
619       dbus_connection_disconnect (connection);
620       return FALSE;
621     }
622
623   if (dbus_message_get_reply_serial (message) != -1)
624     {
625       _dbus_verbose ("Client sent a reply to the bus driver, ignoring it\n");
626       return TRUE;
627     }
628   
629   i = 0;
630   while (i < _DBUS_N_ELEMENTS (message_handlers))
631     {
632       if (strcmp (message_handlers[i].name, name) == 0)
633         {
634           _dbus_verbose ("Running driver handler for %s\n", name);
635           if ((* message_handlers[i].handler) (connection, transaction, message, error))
636             {
637               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
638               _dbus_verbose ("Driver handler succeeded\n");
639               return TRUE;
640             }
641           else
642             {
643               _DBUS_ASSERT_ERROR_IS_SET (error);
644               _dbus_verbose ("Driver handler returned failure\n");
645               return FALSE;
646             }
647         }
648       
649       ++i;
650     }
651
652   _dbus_verbose ("No driver handler for %s\n", name);
653
654   dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
655                   "%s does not understand message %s",
656                   DBUS_SERVICE_DBUS, name);
657   
658   return FALSE;
659 }
660
661 void
662 bus_driver_remove_connection (DBusConnection *connection)
663 {
664   /* FIXME Does nothing for now, should unregister the connection
665    * with the bus driver.
666    */
667 }