2003-04-02 Havoc Pennington <hp@redhat.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 (service == NULL)
482     {
483       service = bus_registry_ensure (registry,
484                                      &service_name, connection, transaction, error);
485       if (service == NULL)
486         goto out;
487     }
488
489   current_owner = bus_service_get_primary_owner (service);
490
491   if (old_owner == NULL)
492     {
493       _dbus_assert (current_owner == connection);
494
495       bus_service_set_prohibit_replacement (service,
496                                             (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT));      
497                         
498       service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;      
499     }
500   else if (old_owner == connection)
501     service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER;
502   else if (!((flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING)))
503     service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS;
504   else if (bus_service_get_prohibit_replacement (service))
505     {
506       /* Queue the connection */
507       if (!bus_service_add_owner (service, connection,
508                                   transaction, error))
509         goto out;
510       
511       service_reply = DBUS_SERVICE_REPLY_IN_QUEUE;
512     }
513   else
514     {
515       /* Replace the current owner */
516
517       /* We enqueue the new owner and remove the first one because
518        * that will cause ServiceAcquired and ServiceLost messages to
519        * be sent.
520        */
521       
522       /* FIXME this is broken, if the remove_owner fails
523        * we don't undo the add_owner
524        * (easiest fix is probably to move all this to
525        * services.c and have a single routine for it)
526        */
527       
528       if (!bus_service_add_owner (service, connection,
529                                   transaction, error))
530         goto out;
531       
532       if (!bus_service_remove_owner (service, old_owner,
533                                      transaction, error))
534         goto out;
535       
536       _dbus_assert (connection == bus_service_get_primary_owner (service));
537       service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
538     }
539
540   if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0))
541     {
542       BUS_SET_OOM (error);
543       goto out;
544     }
545
546   if (!bus_transaction_send_message (transaction, connection, reply))
547     {
548       BUS_SET_OOM (error);
549       goto out;
550     }
551
552   retval = TRUE;
553   
554  out:
555   dbus_free (name);
556   if (reply)
557     dbus_message_unref (reply);
558   return retval;
559
560
561 static dbus_bool_t
562 bus_driver_handle_service_exists (DBusConnection *connection,
563                                   BusTransaction *transaction,
564                                   DBusMessage    *message,
565                                   DBusError      *error)
566 {
567   DBusMessage *reply;
568   DBusString service_name;
569   BusService *service;
570   char *name;
571   dbus_bool_t retval;
572   BusRegistry *registry;
573
574   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
575   
576   registry = bus_connection_get_registry (connection);
577   
578   if (!dbus_message_get_args (message, error,
579                               DBUS_TYPE_STRING, &name,
580                               0))
581     return FALSE;
582
583   retval = FALSE;
584   
585   _dbus_string_init_const (&service_name, name);
586   service = bus_registry_lookup (registry, &service_name);
587  
588   reply = dbus_message_new_reply (message);
589   if (reply == NULL)
590     {
591       BUS_SET_OOM (error);
592       goto out;
593     }
594   
595   if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
596     {
597       BUS_SET_OOM (error);
598       goto out;
599     }
600
601   if (!dbus_message_append_args (reply,
602                                  DBUS_TYPE_UINT32, service != NULL,
603                                  0))
604     {
605       BUS_SET_OOM (error);
606       goto out;
607     }
608
609   if (!bus_transaction_send_message (transaction, connection, reply))
610     {
611       BUS_SET_OOM (error);
612       goto out;
613     }
614
615   retval = TRUE;
616   
617  out:
618   if (reply)
619     dbus_message_unref (reply);
620   dbus_free (name);
621
622   return retval;
623 }
624
625 static dbus_bool_t
626 bus_driver_handle_activate_service (DBusConnection *connection,
627                                     BusTransaction *transaction,
628                                     DBusMessage    *message,
629                                     DBusError      *error)
630 {
631   dbus_uint32_t flags;
632   char *name;
633   dbus_bool_t retval;
634   BusActivation *activation;
635
636   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
637   
638   activation = bus_connection_get_activation (connection);
639   
640   if (!dbus_message_get_args (message, error,
641                               DBUS_TYPE_STRING, &name,
642                               DBUS_TYPE_UINT32, &flags,
643                               0))
644     return FALSE;
645
646   retval = FALSE;
647
648   if (!bus_activation_activate_service (activation, connection, transaction,
649                                         message, name, error))
650     goto out;
651
652   retval = TRUE;
653   
654  out:
655   dbus_free (name);
656   return retval;
657 }
658
659 /* For speed it might be useful to sort this in order of
660  * frequency of use (but doesn't matter with only a few items
661  * anyhow)
662  */
663 struct
664 {
665   const char *name;
666   dbus_bool_t (* handler) (DBusConnection *connection,
667                            BusTransaction *transaction,
668                            DBusMessage    *message,
669                            DBusError      *error);
670 } message_handlers[] = {
671   { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
672   { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
673   { DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
674   { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
675   { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
676 };
677
678 dbus_bool_t
679 bus_driver_handle_message (DBusConnection *connection,
680                            BusTransaction *transaction,
681                            DBusMessage    *message,
682                            DBusError      *error)
683 {
684   const char *name, *sender;
685   int i;
686
687   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
688   
689   _dbus_verbose ("Driver got a message: %s\n",
690                  dbus_message_get_name (message));
691   
692   name = dbus_message_get_name (message);
693   sender = dbus_message_get_sender (message);
694
695   if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0))
696     {
697       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
698                       "Client tried to send a message other than %s without being registered",
699                       DBUS_MESSAGE_HELLO);
700
701       dbus_connection_disconnect (connection);
702       return FALSE;
703     }
704
705   i = 0;
706   while (i < _DBUS_N_ELEMENTS (message_handlers))
707     {
708       if (strcmp (message_handlers[i].name, name) == 0)
709         {
710           if ((* message_handlers[i].handler) (connection, transaction, message, error))
711             return TRUE;
712           else
713             return FALSE;
714         }
715       
716       ++i;
717     }
718
719   dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
720                   "%s does not understand message %s",
721                   DBUS_SERVICE_DBUS, name);
722   
723   return FALSE;
724 }
725
726 void
727 bus_driver_remove_connection (DBusConnection *connection)
728 {
729   /* FIXME Does nothing for now, should unregister the connection
730    * with the bus driver.
731    */
732 }