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