2003-06-22 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_MESSAGE_SERVICE_DELETED,
53                               DBUS_SERVICE_BROADCAST);
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                                  DBUS_TYPE_INVALID))
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_MESSAGE_SERVICE_CREATED,
87                               DBUS_SERVICE_BROADCAST);
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                                  DBUS_TYPE_INVALID))
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 (DBUS_MESSAGE_SERVICE_LOST,
127                               bus_connection_get_name (connection));
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                                  DBUS_TYPE_INVALID))
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 (DBUS_MESSAGE_SERVICE_ACQUIRED,
167                               bus_connection_get_name (connection));
168
169   if (message == NULL)
170     {
171       BUS_SET_OOM (error);
172       return FALSE;
173     }
174   
175   if (!dbus_message_append_args (message,
176                                  DBUS_TYPE_STRING, service_name,
177                                  DBUS_TYPE_INVALID))
178     {
179       dbus_message_unref (message);
180       BUS_SET_OOM (error);
181       return FALSE;
182     }
183
184   if (!bus_transaction_send_from_driver (transaction, connection, message))
185     {
186       dbus_message_unref (message);
187       BUS_SET_OOM (error);
188       return FALSE;
189     }
190   else
191     {
192       dbus_message_unref (message);
193       return TRUE;
194     }
195 }
196
197 static dbus_bool_t
198 create_unique_client_name (BusRegistry *registry,
199                            DBusString  *str)
200 {
201   /* We never want to use the same unique client name twice, because
202    * we want to guarantee that if you send a message to a given unique
203    * name, you always get the same application. So we use two numbers
204    * for INT_MAX * INT_MAX combinations, should be pretty safe against
205    * wraparound.
206    */
207   /* FIXME these should be in BusRegistry rather than static vars */
208   static int next_major_number = 0;
209   static int next_minor_number = 0;
210   int len;
211   
212   len = _dbus_string_get_length (str);
213   
214   while (TRUE)
215     {
216       /* start out with 1-0, go to 1-1, 1-2, 1-3,
217        * up to 1-MAXINT, then 2-0, 2-1, etc.
218        */
219       if (next_minor_number <= 0)
220         {
221           next_major_number += 1;
222           next_minor_number = 0;
223           if (next_major_number <= 0)
224             _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
225         }
226
227       _dbus_assert (next_major_number > 0);
228       _dbus_assert (next_minor_number >= 0);
229
230       /* appname:MAJOR-MINOR */
231       
232       if (!_dbus_string_append (str, ":"))
233         return FALSE;
234       
235       if (!_dbus_string_append_int (str, next_major_number))
236         return FALSE;
237
238       if (!_dbus_string_append (str, "-"))
239         return FALSE;
240       
241       if (!_dbus_string_append_int (str, next_minor_number))
242         return FALSE;
243
244       next_minor_number += 1;
245       
246       /* Check if a client with the name exists */
247       if (bus_registry_lookup (registry, str) == NULL)
248         break;
249
250       /* drop the number again, try the next one. */
251       _dbus_string_set_length (str, len);
252     }
253
254   return TRUE;
255 }
256
257 static dbus_bool_t
258 bus_driver_handle_hello (DBusConnection *connection,
259                          BusTransaction *transaction,
260                          DBusMessage    *message,
261                          DBusError      *error)
262 {
263   DBusString unique_name;
264   BusService *service;
265   dbus_bool_t retval;
266   BusRegistry *registry;
267   BusConnections *connections;
268
269   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
270
271   /* Note that when these limits are exceeded we don't disconnect the
272    * connection; we just sort of leave it hanging there until it times
273    * out or disconnects itself or is dropped due to the max number of
274    * incomplete connections. It's even OK if the connection wants to
275    * retry the hello message, we support that.
276    */
277   connections = bus_connection_get_connections (connection);
278   if (!bus_connections_check_limits (connections, connection,
279                                      error))
280     {
281       _DBUS_ASSERT_ERROR_IS_SET (error);
282       return FALSE;
283     }
284   
285   if (!_dbus_string_init (&unique_name))
286     {
287       BUS_SET_OOM (error);
288       return FALSE;
289     }
290
291   retval = FALSE;
292
293   registry = bus_connection_get_registry (connection);
294   
295   if (!create_unique_client_name (registry, &unique_name))
296     {
297       BUS_SET_OOM (error);
298       goto out_0;
299     }
300
301   if (!bus_connection_complete (connection, &unique_name, error))
302     {
303       _DBUS_ASSERT_ERROR_IS_SET (error);
304       goto out_0;
305     }
306   
307   if (!dbus_message_set_sender (message,
308                                 bus_connection_get_name (connection)))
309     {
310       BUS_SET_OOM (error);
311       goto out_0;
312     }
313   
314   if (!bus_driver_send_welcome_message (connection, message, transaction, error))
315     goto out_0;
316
317   /* Create the service */
318   service = bus_registry_ensure (registry,
319                                  &unique_name, connection, transaction, error);
320   if (service == NULL)
321     goto out_0;
322   
323   bus_service_set_prohibit_replacement (service, TRUE);
324
325   retval = TRUE;
326   
327  out_0:
328   _dbus_string_free (&unique_name);
329   return retval;
330 }
331
332 static dbus_bool_t
333 bus_driver_send_welcome_message (DBusConnection *connection,
334                                  DBusMessage    *hello_message,
335                                  BusTransaction *transaction,
336                                  DBusError      *error)
337 {
338   DBusMessage *welcome;
339   const char *name;
340
341   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
342   
343   name = bus_connection_get_name (connection);
344   _dbus_assert (name != NULL);
345   
346   welcome = dbus_message_new_reply (hello_message);
347   if (welcome == NULL)
348     {
349       BUS_SET_OOM (error);
350       return FALSE;
351     }
352   
353   if (!dbus_message_append_args (welcome,
354                                  DBUS_TYPE_STRING, name,
355                                  DBUS_TYPE_INVALID))
356     {
357       dbus_message_unref (welcome);
358       BUS_SET_OOM (error);
359       return FALSE;
360     }
361
362   if (!bus_transaction_send_from_driver (transaction, connection, welcome))
363     {
364       dbus_message_unref (welcome);
365       BUS_SET_OOM (error);
366       return FALSE;
367     }
368   else
369     {
370       dbus_message_unref (welcome);
371       return TRUE;
372     }
373 }
374
375 static dbus_bool_t
376 bus_driver_handle_list_services (DBusConnection *connection,
377                                  BusTransaction *transaction,
378                                  DBusMessage    *message,
379                                  DBusError      *error)
380 {
381   DBusMessage *reply;
382   int len;
383   char **services;
384   BusRegistry *registry;
385
386   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
387   
388   registry = bus_connection_get_registry (connection);
389   
390   reply = dbus_message_new_reply (message);
391   if (reply == NULL)
392     {
393       BUS_SET_OOM (error);
394       return FALSE;
395     }
396
397   if (!bus_registry_list_services (registry, &services, &len))
398     {
399       dbus_message_unref (reply);
400       BUS_SET_OOM (error);
401       return FALSE;
402     }
403   
404   if (!dbus_message_append_args (reply,
405                                  DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, services, len,
406                                  DBUS_TYPE_INVALID))
407     {
408       dbus_free_string_array (services);
409       dbus_message_unref (reply);
410       BUS_SET_OOM (error);
411       return FALSE;
412     }
413
414   dbus_free_string_array (services);
415   
416   if (!bus_transaction_send_from_driver (transaction, connection, reply))
417     {
418       dbus_message_unref (reply);
419       BUS_SET_OOM (error);
420       return FALSE;
421     }
422   else
423     {
424       dbus_message_unref (reply);
425       return TRUE;
426     }
427 }
428
429 static dbus_bool_t
430 bus_driver_handle_acquire_service (DBusConnection *connection,
431                                    BusTransaction *transaction,
432                                    DBusMessage    *message,
433                                    DBusError      *error)
434 {
435   DBusMessage *reply;
436   DBusString service_name;
437   char *name;
438   int service_reply;
439   int flags;
440   dbus_bool_t retval;
441   BusRegistry *registry;
442
443   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
444   
445   registry = bus_connection_get_registry (connection);
446   
447   if (!dbus_message_get_args (message, error,
448                               DBUS_TYPE_STRING, &name,
449                               DBUS_TYPE_UINT32, &flags,
450                               DBUS_TYPE_INVALID))
451     return FALSE;
452   
453   _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags);
454   
455   retval = FALSE;
456   reply = NULL;
457
458   _dbus_string_init_const (&service_name, name);
459
460   if (!bus_registry_acquire_service (registry, connection,
461                                      &service_name, flags,
462                                      &service_reply, transaction,
463                                      error))
464     goto out;
465   
466   reply = dbus_message_new_reply (message);
467   if (reply == NULL)
468     {
469       BUS_SET_OOM (error);
470       goto out;
471     }
472
473   if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, DBUS_TYPE_INVALID))
474     {
475       BUS_SET_OOM (error);
476       goto out;
477     }
478
479   if (!bus_transaction_send_from_driver (transaction, connection, reply))
480     {
481       BUS_SET_OOM (error);
482       goto out;
483     }
484
485   retval = TRUE;
486   
487  out:
488   dbus_free (name);
489   if (reply)
490     dbus_message_unref (reply);
491   return retval;
492
493
494 static dbus_bool_t
495 bus_driver_handle_service_exists (DBusConnection *connection,
496                                   BusTransaction *transaction,
497                                   DBusMessage    *message,
498                                   DBusError      *error)
499 {
500   DBusMessage *reply;
501   DBusString service_name;
502   BusService *service;
503   char *name;
504   dbus_bool_t retval;
505   BusRegistry *registry;
506
507   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
508   
509   registry = bus_connection_get_registry (connection);
510   
511   if (!dbus_message_get_args (message, error,
512                               DBUS_TYPE_STRING, &name,
513                               DBUS_TYPE_INVALID))
514     return FALSE;
515
516   retval = FALSE;
517   
518   _dbus_string_init_const (&service_name, name);
519   service = bus_registry_lookup (registry, &service_name);
520  
521   reply = dbus_message_new_reply (message);
522   if (reply == NULL)
523     {
524       BUS_SET_OOM (error);
525       goto out;
526     }
527
528   if (!dbus_message_append_args (reply,
529                                  DBUS_TYPE_UINT32, service != NULL,
530                                  0))
531     {
532       BUS_SET_OOM (error);
533       goto out;
534     }
535
536   if (!bus_transaction_send_from_driver (transaction, connection, reply))
537     {
538       BUS_SET_OOM (error);
539       goto out;
540     }
541
542   retval = TRUE;
543   
544  out:
545   if (reply)
546     dbus_message_unref (reply);
547   dbus_free (name);
548
549   return retval;
550 }
551
552 static dbus_bool_t
553 bus_driver_handle_activate_service (DBusConnection *connection,
554                                     BusTransaction *transaction,
555                                     DBusMessage    *message,
556                                     DBusError      *error)
557 {
558   dbus_uint32_t flags;
559   char *name;
560   dbus_bool_t retval;
561   BusActivation *activation;
562
563   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
564   
565   activation = bus_connection_get_activation (connection);
566   
567   if (!dbus_message_get_args (message, error,
568                               DBUS_TYPE_STRING, &name,
569                               DBUS_TYPE_UINT32, &flags,
570                               DBUS_TYPE_INVALID))
571     {
572       _DBUS_ASSERT_ERROR_IS_SET (error);
573       _dbus_verbose ("No memory to get arguments to ActivateService\n");
574       return FALSE;
575     }
576
577   retval = FALSE;
578
579   if (!bus_activation_activate_service (activation, connection, transaction,
580                                         message, name, error))
581     {
582       _DBUS_ASSERT_ERROR_IS_SET (error);
583       _dbus_verbose ("bus_activation_activate_service() failed\n");
584       goto out;
585     }
586
587   retval = TRUE;
588   
589  out:
590   dbus_free (name);
591   return retval;
592 }
593
594 /* For speed it might be useful to sort this in order of
595  * frequency of use (but doesn't matter with only a few items
596  * anyhow)
597  */
598 struct
599 {
600   const char *name;
601   dbus_bool_t (* handler) (DBusConnection *connection,
602                            BusTransaction *transaction,
603                            DBusMessage    *message,
604                            DBusError      *error);
605 } message_handlers[] = {
606   { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
607   { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
608   { DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
609   { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
610   { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
611 };
612
613 dbus_bool_t
614 bus_driver_handle_message (DBusConnection *connection,
615                            BusTransaction *transaction,
616                            DBusMessage    *message,
617                            DBusError      *error)
618 {
619   const char *name, *sender;
620   int i;
621
622   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
623   
624   _dbus_verbose ("Driver got a message: %s\n",
625                  dbus_message_get_name (message));
626   
627   name = dbus_message_get_name (message);
628   sender = dbus_message_get_sender (message);
629
630   /* security checks should have kept this from getting here */
631   _dbus_assert (sender != NULL || strcmp (name, DBUS_MESSAGE_HELLO) == 0);
632
633   if (dbus_message_get_reply_serial (message) == 0)
634     {
635       _dbus_verbose ("Client sent a reply to the bus driver, ignoring it\n");
636       return TRUE;
637     }
638   
639   i = 0;
640   while (i < _DBUS_N_ELEMENTS (message_handlers))
641     {
642       if (strcmp (message_handlers[i].name, name) == 0)
643         {
644           _dbus_verbose ("Running driver handler for %s\n", name);
645           if ((* message_handlers[i].handler) (connection, transaction, message, error))
646             {
647               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
648               _dbus_verbose ("Driver handler succeeded\n");
649               return TRUE;
650             }
651           else
652             {
653               _DBUS_ASSERT_ERROR_IS_SET (error);
654               _dbus_verbose ("Driver handler returned failure\n");
655               return FALSE;
656             }
657         }
658       
659       ++i;
660     }
661
662   _dbus_verbose ("No driver handler for %s\n", name);
663
664   dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
665                   "%s does not understand message %s",
666                   DBUS_SERVICE_DBUS, name);
667   
668   return FALSE;
669 }
670
671 void
672 bus_driver_remove_connection (DBusConnection *connection)
673 {
674   /* FIXME Does nothing for now, should unregister the connection
675    * with the bus driver.
676    */
677 }