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