2003-04-06 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  *
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 dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
35                                                     DBusMessage    *hello_message,
36                                                     BusTransaction *transaction,
37                                                     DBusError      *error);
38
39 dbus_bool_t
40 bus_driver_send_service_deleted (const char     *service_name,
41                                  BusTransaction *transaction,
42                                  DBusError      *error)
43 {
44   DBusMessage *message;
45   dbus_bool_t retval;
46
47   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
48   
49   _dbus_verbose ("sending service deleted: %s\n", service_name);
50
51   message = dbus_message_new (DBUS_SERVICE_BROADCAST,
52                               DBUS_MESSAGE_SERVICE_DELETED);
53   if (message == NULL)
54     {
55       BUS_SET_OOM (error);
56       return FALSE;
57     }
58   
59   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
60       !dbus_message_append_args (message,
61                                  DBUS_TYPE_STRING, service_name,
62                                  0))
63     {
64       dbus_message_unref (message);
65       BUS_SET_OOM (error);
66       return FALSE;
67     }
68
69   retval = bus_dispatch_broadcast_message (transaction, message, error);
70   dbus_message_unref (message);
71
72   return retval;
73 }
74
75 dbus_bool_t
76 bus_driver_send_service_created (const char     *service_name,
77                                  BusTransaction *transaction,
78                                  DBusError      *error)
79 {
80   DBusMessage *message;
81   dbus_bool_t retval;
82
83   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
84   
85   message = dbus_message_new (DBUS_SERVICE_BROADCAST,
86                               DBUS_MESSAGE_SERVICE_CREATED);
87   if (message == NULL)
88     {
89       BUS_SET_OOM (error);
90       return FALSE;
91     }
92   
93   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
94     {
95       dbus_message_unref (message);
96       BUS_SET_OOM (error);
97       return FALSE;
98     }
99   
100   if (!dbus_message_append_args (message,
101                                  DBUS_TYPE_STRING, service_name,
102                                  0))
103     {
104       dbus_message_unref (message);
105       BUS_SET_OOM (error);
106       return FALSE;
107     }
108   
109   retval = bus_dispatch_broadcast_message (transaction, message, error);
110   dbus_message_unref (message);
111
112   return retval;
113 }
114
115 dbus_bool_t
116 bus_driver_send_service_lost (DBusConnection *connection,
117                               const char     *service_name,
118                               BusTransaction *transaction,
119                               DBusError      *error)
120 {
121   DBusMessage *message;
122
123   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
124   
125   message = dbus_message_new (bus_connection_get_name (connection),
126                               DBUS_MESSAGE_SERVICE_LOST);
127   if (message == NULL)
128     {
129       BUS_SET_OOM (error);
130       return FALSE;
131     }
132   
133   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
134     {
135       dbus_message_unref (message);
136       BUS_SET_OOM (error);
137       return FALSE;
138     }
139   
140   if (!dbus_message_append_args (message,
141                                  DBUS_TYPE_STRING, service_name,
142                                  0))
143     {
144       dbus_message_unref (message);
145       BUS_SET_OOM (error);
146       return FALSE;
147     }
148
149   if (!bus_transaction_send_message (transaction, connection, message))
150     {
151       dbus_message_unref (message);
152       BUS_SET_OOM (error);
153       return FALSE;
154     }
155   else
156     {
157       dbus_message_unref (message);
158       return TRUE;
159     }
160 }
161
162 dbus_bool_t
163 bus_driver_send_service_acquired (DBusConnection *connection,
164                                   const char     *service_name,
165                                   BusTransaction *transaction,
166                                   DBusError      *error)
167 {
168   DBusMessage *message;
169
170   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
171   
172   message = dbus_message_new (bus_connection_get_name (connection),
173                               DBUS_MESSAGE_SERVICE_ACQUIRED);
174   if (message == NULL)
175     {
176       BUS_SET_OOM (error);
177       return FALSE;
178     }
179   
180   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
181     {
182       dbus_message_unref (message);
183       BUS_SET_OOM (error);
184       return FALSE;
185     }
186   
187   if (!dbus_message_append_args (message,
188                                  DBUS_TYPE_STRING, service_name,
189                                  0))
190     {
191       dbus_message_unref (message);
192       BUS_SET_OOM (error);
193       return FALSE;
194     }
195
196   if (!bus_transaction_send_message (transaction, connection, message))
197     {
198       dbus_message_unref (message);
199       BUS_SET_OOM (error);
200       return FALSE;
201     }
202   else
203     {
204       dbus_message_unref (message);
205       return TRUE;
206     }
207 }
208
209 static dbus_bool_t
210 create_unique_client_name (BusRegistry *registry,
211                            DBusString  *str)
212 {
213   /* We never want to use the same unique client name twice, because
214    * we want to guarantee that if you send a message to a given unique
215    * name, you always get the same application. So we use two numbers
216    * for INT_MAX * INT_MAX combinations, should be pretty safe against
217    * wraparound.
218    */
219   static int next_major_number = 0;
220   static int next_minor_number = 0;
221   int len;
222
223   len = _dbus_string_get_length (str);
224   
225   while (TRUE)
226     {
227       /* start out with 1-0, go to 1-1, 1-2, 1-3,
228        * up to 1-MAXINT, then 2-0, 2-1, etc.
229        */
230       if (next_minor_number <= 0)
231         {
232           next_major_number += 1;
233           next_minor_number = 0;
234           if (next_major_number <= 0)
235             _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
236         }
237
238       _dbus_assert (next_major_number > 0);
239       _dbus_assert (next_minor_number >= 0);
240
241       /* appname:MAJOR-MINOR */
242       
243       if (!_dbus_string_append (str, ":"))
244         return FALSE;
245       
246       if (!_dbus_string_append_int (str, next_major_number))
247         return FALSE;
248
249       if (!_dbus_string_append (str, "-"))
250         return FALSE;
251       
252       if (!_dbus_string_append_int (str, next_minor_number))
253         return FALSE;
254
255       next_minor_number += 1;
256       
257       /* Check if a client with the name exists */
258       if (bus_registry_lookup (registry, str) == NULL)
259         break;
260
261       /* drop the number again, try the next one. */
262       _dbus_string_set_length (str, len);
263     }
264
265   return TRUE;
266 }
267
268 static dbus_bool_t
269 bus_driver_handle_hello (DBusConnection *connection,
270                          BusTransaction *transaction,
271                          DBusMessage    *message,
272                          DBusError      *error)
273 {
274   DBusString unique_name;
275   BusService *service;
276   dbus_bool_t retval;
277   BusRegistry *registry;
278
279   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
280   
281   if (!_dbus_string_init (&unique_name))
282     {
283       BUS_SET_OOM (error);
284       return FALSE;
285     }
286
287   retval = FALSE;
288
289   registry = bus_connection_get_registry (connection);
290   
291   if (!create_unique_client_name (registry, &unique_name))
292     {
293       BUS_SET_OOM (error);
294       goto out_0;
295     }
296
297   if (!bus_connection_set_name (connection, &unique_name))
298     {
299       BUS_SET_OOM (error);
300       goto out_0;
301     }
302   
303   if (!dbus_message_set_sender (message,
304                                 bus_connection_get_name (connection)))
305     {
306       BUS_SET_OOM (error);
307       goto out_0;
308     }
309   
310   if (!bus_driver_send_welcome_message (connection, message, transaction, error))
311     goto out_0;
312
313   /* Create the service */
314   service = bus_registry_ensure (registry,
315                                  &unique_name, connection, transaction, error);
316   if (service == NULL)
317     goto out_0;
318   
319   bus_service_set_prohibit_replacement (service, TRUE);
320
321   retval = TRUE;
322   
323  out_0:
324   _dbus_string_free (&unique_name);
325   return retval;
326 }
327
328 static dbus_bool_t
329 bus_driver_send_welcome_message (DBusConnection *connection,
330                                  DBusMessage    *hello_message,
331                                  BusTransaction *transaction,
332                                  DBusError      *error)
333 {
334   DBusMessage *welcome;
335   const char *name;
336
337   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
338   
339   name = bus_connection_get_name (connection);
340   _dbus_assert (name != NULL);
341   
342   welcome = dbus_message_new_reply (hello_message);
343   if (welcome == NULL)
344     {
345       BUS_SET_OOM (error);
346       return FALSE;
347     }
348   
349   if (!dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS))
350     {
351       dbus_message_unref (welcome);
352       BUS_SET_OOM (error);
353       return FALSE;
354     }
355   
356   if (!dbus_message_append_args (welcome,
357                                  DBUS_TYPE_STRING, name,
358                                  NULL))
359     {
360       dbus_message_unref (welcome);
361       BUS_SET_OOM (error);
362       return FALSE;
363     }
364
365   if (!bus_transaction_send_message (transaction, connection, welcome))
366     {
367       dbus_message_unref (welcome);
368       BUS_SET_OOM (error);
369       return FALSE;
370     }
371   else
372     {
373       dbus_message_unref (welcome);
374       return TRUE;
375     }
376 }
377
378 static dbus_bool_t
379 bus_driver_handle_list_services (DBusConnection *connection,
380                                  BusTransaction *transaction,
381                                  DBusMessage    *message,
382                                  DBusError      *error)
383 {
384   DBusMessage *reply;
385   int len;
386   char **services;
387   BusRegistry *registry;
388
389   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
390   
391   registry = bus_connection_get_registry (connection);
392   
393   reply = dbus_message_new_reply (message);
394   if (reply == NULL)
395     {
396       BUS_SET_OOM (error);
397       return FALSE;
398     }
399
400   if (!bus_registry_list_services (registry, &services, &len))
401     {
402       dbus_message_unref (reply);
403       BUS_SET_OOM (error);
404       return FALSE;
405     }
406   
407   if (!dbus_message_append_args (reply,
408                                  DBUS_TYPE_STRING_ARRAY, services, len,
409                                  0))
410     {
411       dbus_free_string_array (services);
412       dbus_message_unref (reply);
413       BUS_SET_OOM (error);
414       return FALSE;
415     }
416
417   dbus_free_string_array (services);
418   
419   if (!bus_transaction_send_message (transaction, connection, reply))
420     {
421       dbus_message_unref (reply);
422       BUS_SET_OOM (error);
423       return FALSE;
424     }
425   else
426     {
427       dbus_message_unref (reply);
428       return TRUE;
429     }
430 }
431
432 static dbus_bool_t
433 bus_driver_handle_acquire_service (DBusConnection *connection,
434                                    BusTransaction *transaction,
435                                    DBusMessage    *message,
436                                    DBusError      *error)
437 {
438   DBusMessage *reply;
439   DBusString service_name;
440   BusService *service;  
441   char *name;
442   int service_reply;
443   int flags;
444   dbus_bool_t retval;
445   DBusConnection *old_owner;
446   DBusConnection *current_owner;
447   BusRegistry *registry;
448
449   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
450   
451   registry = bus_connection_get_registry (connection);
452   
453   if (!dbus_message_get_args (message,
454                               error,
455                               DBUS_TYPE_STRING, &name,
456                               DBUS_TYPE_UINT32, &flags,
457                               0))
458     return FALSE;
459   
460   _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags);
461
462   retval = FALSE;
463   reply = NULL;
464
465   _dbus_string_init_const (&service_name, name);
466   
467   service = bus_registry_lookup (registry, &service_name);
468
469   if (service != NULL)
470     old_owner = bus_service_get_primary_owner (service);
471   else
472     old_owner = NULL;  
473   
474   reply = dbus_message_new_reply (message);
475   if (reply == NULL)
476     {
477       BUS_SET_OOM (error);
478       goto out;
479     }
480
481   if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
482     {
483       BUS_SET_OOM (error);
484       goto out;
485     }
486       
487   if (service == NULL)
488     {
489       service = bus_registry_ensure (registry,
490                                      &service_name, connection, transaction, error);
491       if (service == NULL)
492         goto out;
493     }
494
495   current_owner = bus_service_get_primary_owner (service);
496
497   if (old_owner == NULL)
498     {
499       _dbus_assert (current_owner == connection);
500
501       bus_service_set_prohibit_replacement (service,
502                                             (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT));      
503                         
504       service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;      
505     }
506   else if (old_owner == connection)
507     service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER;
508   else if (!((flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING)))
509     service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS;
510   else if (bus_service_get_prohibit_replacement (service))
511     {
512       /* Queue the connection */
513       if (!bus_service_add_owner (service, connection,
514                                   transaction, error))
515         goto out;
516       
517       service_reply = DBUS_SERVICE_REPLY_IN_QUEUE;
518     }
519   else
520     {
521       /* Replace the current owner */
522
523       /* We enqueue the new owner and remove the first one because
524        * that will cause ServiceAcquired and ServiceLost messages to
525        * be sent.
526        */
527       
528       /* FIXME this is broken, if the remove_owner fails
529        * we don't undo the add_owner
530        * (easiest fix is probably to move all this to
531        * services.c and have a single routine for it)
532        */
533       
534       if (!bus_service_add_owner (service, connection,
535                                   transaction, error))
536         goto out;
537       
538       if (!bus_service_remove_owner (service, old_owner,
539                                      transaction, error))
540         goto out;
541       
542       _dbus_assert (connection == bus_service_get_primary_owner (service));
543       service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
544     }
545
546   if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0))
547     {
548       BUS_SET_OOM (error);
549       goto out;
550     }
551
552   if (!bus_transaction_send_message (transaction, connection, reply))
553     {
554       BUS_SET_OOM (error);
555       goto out;
556     }
557
558   retval = TRUE;
559   
560  out:
561   dbus_free (name);
562   if (reply)
563     dbus_message_unref (reply);
564   return retval;
565
566
567 static dbus_bool_t
568 bus_driver_handle_service_exists (DBusConnection *connection,
569                                   BusTransaction *transaction,
570                                   DBusMessage    *message,
571                                   DBusError      *error)
572 {
573   DBusMessage *reply;
574   DBusString service_name;
575   BusService *service;
576   char *name;
577   dbus_bool_t retval;
578   BusRegistry *registry;
579
580   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
581   
582   registry = bus_connection_get_registry (connection);
583   
584   if (!dbus_message_get_args (message, error,
585                               DBUS_TYPE_STRING, &name,
586                               0))
587     return FALSE;
588
589   retval = FALSE;
590   
591   _dbus_string_init_const (&service_name, name);
592   service = bus_registry_lookup (registry, &service_name);
593  
594   reply = dbus_message_new_reply (message);
595   if (reply == NULL)
596     {
597       BUS_SET_OOM (error);
598       goto out;
599     }
600   
601   if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
602     {
603       BUS_SET_OOM (error);
604       goto out;
605     }
606
607   if (!dbus_message_append_args (reply,
608                                  DBUS_TYPE_UINT32, service != NULL,
609                                  0))
610     {
611       BUS_SET_OOM (error);
612       goto out;
613     }
614
615   if (!bus_transaction_send_message (transaction, connection, reply))
616     {
617       BUS_SET_OOM (error);
618       goto out;
619     }
620
621   retval = TRUE;
622   
623  out:
624   if (reply)
625     dbus_message_unref (reply);
626   dbus_free (name);
627
628   return retval;
629 }
630
631 static dbus_bool_t
632 bus_driver_handle_activate_service (DBusConnection *connection,
633                                     BusTransaction *transaction,
634                                     DBusMessage    *message,
635                                     DBusError      *error)
636 {
637   dbus_uint32_t flags;
638   char *name;
639   dbus_bool_t retval;
640   BusActivation *activation;
641
642   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
643   
644   activation = bus_connection_get_activation (connection);
645   
646   if (!dbus_message_get_args (message, error,
647                               DBUS_TYPE_STRING, &name,
648                               DBUS_TYPE_UINT32, &flags,
649                               0))
650     return FALSE;
651
652   retval = FALSE;
653
654   if (!bus_activation_activate_service (activation, connection, transaction,
655                                         message, name, error))
656     goto out;
657
658   retval = TRUE;
659   
660  out:
661   dbus_free (name);
662   return retval;
663 }
664
665 /* For speed it might be useful to sort this in order of
666  * frequency of use (but doesn't matter with only a few items
667  * anyhow)
668  */
669 struct
670 {
671   const char *name;
672   dbus_bool_t (* handler) (DBusConnection *connection,
673                            BusTransaction *transaction,
674                            DBusMessage    *message,
675                            DBusError      *error);
676 } message_handlers[] = {
677   { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
678   { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
679   { DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
680   { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
681   { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
682 };
683
684 dbus_bool_t
685 bus_driver_handle_message (DBusConnection *connection,
686                            BusTransaction *transaction,
687                            DBusMessage    *message,
688                            DBusError      *error)
689 {
690   const char *name, *sender;
691   int i;
692
693   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
694   
695   _dbus_verbose ("Driver got a message: %s\n",
696                  dbus_message_get_name (message));
697   
698   name = dbus_message_get_name (message);
699   sender = dbus_message_get_sender (message);
700
701   if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0))
702     {
703       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
704                       "Client tried to send a message other than %s without being registered",
705                       DBUS_MESSAGE_HELLO);
706
707       dbus_connection_disconnect (connection);
708       return FALSE;
709     }
710
711   i = 0;
712   while (i < _DBUS_N_ELEMENTS (message_handlers))
713     {
714       if (strcmp (message_handlers[i].name, name) == 0)
715         {
716           if ((* message_handlers[i].handler) (connection, transaction, message, error))
717             return TRUE;
718           else
719             return FALSE;
720         }
721       
722       ++i;
723     }
724
725   dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
726                   "%s does not understand message %s",
727                   DBUS_SERVICE_DBUS, name);
728   
729   return FALSE;
730 }
731
732 void
733 bus_driver_remove_connection (DBusConnection *connection)
734 {
735   /* FIXME Does nothing for now, should unregister the connection
736    * with the bus driver.
737    */
738 }