Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

driver.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* driver.c  Bus client (driver)
00003  *
00004  * Copyright (C) 2003 CodeFactory AB
00005  * Copyright (C) 2003 Red Hat, Inc.
00006  *
00007  * Licensed under the Academic Free License version 1.2
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include "activation.h"
00026 #include "connection.h"
00027 #include "driver.h"
00028 #include "dispatch.h"
00029 #include "services.h"
00030 #include "utils.h"
00031 #include <dbus/dbus-string.h>
00032 #include <dbus/dbus-internals.h>
00033 #include <string.h>
00034 
00035 static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
00036                                                     DBusMessage    *hello_message,
00037                                                     BusTransaction *transaction,
00038                                                     DBusError      *error);
00039 
00040 dbus_bool_t
00041 bus_driver_send_service_deleted (const char     *service_name,
00042                                  BusTransaction *transaction,
00043                                  DBusError      *error)
00044 {
00045   DBusMessage *message;
00046   dbus_bool_t retval;
00047 
00048   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00049   
00050   _dbus_verbose ("sending service deleted: %s\n", service_name);
00051 
00052   message = dbus_message_new (DBUS_MESSAGE_SERVICE_DELETED,
00053                               DBUS_SERVICE_BROADCAST);
00054   if (message == NULL)
00055     {
00056       BUS_SET_OOM (error);
00057       return FALSE;
00058     }
00059   
00060   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
00061       !dbus_message_append_args (message,
00062                                  DBUS_TYPE_STRING, service_name,
00063                                  DBUS_TYPE_INVALID))
00064     {
00065       dbus_message_unref (message);
00066       BUS_SET_OOM (error);
00067       return FALSE;
00068     }
00069 
00070   retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
00071   dbus_message_unref (message);
00072 
00073   return retval;
00074 }
00075 
00076 dbus_bool_t
00077 bus_driver_send_service_created (const char     *service_name,
00078                                  BusTransaction *transaction,
00079                                  DBusError      *error)
00080 {
00081   DBusMessage *message;
00082   dbus_bool_t retval;
00083 
00084   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00085   
00086   message = dbus_message_new (DBUS_MESSAGE_SERVICE_CREATED,
00087                               DBUS_SERVICE_BROADCAST);
00088   if (message == NULL)
00089     {
00090       BUS_SET_OOM (error);
00091       return FALSE;
00092     }
00093   
00094   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
00095     {
00096       dbus_message_unref (message);
00097       BUS_SET_OOM (error);
00098       return FALSE;
00099     }
00100   
00101   if (!dbus_message_append_args (message,
00102                                  DBUS_TYPE_STRING, service_name,
00103                                  DBUS_TYPE_INVALID))
00104     {
00105       dbus_message_unref (message);
00106       BUS_SET_OOM (error);
00107       return FALSE;
00108     }
00109   
00110   retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
00111   dbus_message_unref (message);
00112 
00113   return retval;
00114 }
00115 
00116 dbus_bool_t
00117 bus_driver_send_service_lost (DBusConnection *connection,
00118                               const char     *service_name,
00119                               BusTransaction *transaction,
00120                               DBusError      *error)
00121 {
00122   DBusMessage *message;
00123 
00124   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00125   
00126   message = dbus_message_new (DBUS_MESSAGE_SERVICE_LOST,
00127                               bus_connection_get_name (connection));
00128   if (message == NULL)
00129     {
00130       BUS_SET_OOM (error);
00131       return FALSE;
00132     }
00133   
00134   if (!dbus_message_append_args (message,
00135                                  DBUS_TYPE_STRING, service_name,
00136                                  DBUS_TYPE_INVALID))
00137     {
00138       dbus_message_unref (message);
00139       BUS_SET_OOM (error);
00140       return FALSE;
00141     }
00142 
00143   if (!bus_transaction_send_from_driver (transaction, connection, message))
00144     {
00145       dbus_message_unref (message);
00146       BUS_SET_OOM (error);
00147       return FALSE;
00148     }
00149   else
00150     {
00151       dbus_message_unref (message);
00152       return TRUE;
00153     }
00154 }
00155 
00156 dbus_bool_t
00157 bus_driver_send_service_acquired (DBusConnection *connection,
00158                                   const char     *service_name,
00159                                   BusTransaction *transaction,
00160                                   DBusError      *error)
00161 {
00162   DBusMessage *message;
00163 
00164   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00165   
00166   message = dbus_message_new (DBUS_MESSAGE_SERVICE_ACQUIRED,
00167                               bus_connection_get_name (connection));
00168 
00169   if (message == NULL)
00170     {
00171       BUS_SET_OOM (error);
00172       return FALSE;
00173     }
00174   
00175   if (!dbus_message_append_args (message,
00176                                  DBUS_TYPE_STRING, service_name,
00177                                  DBUS_TYPE_INVALID))
00178     {
00179       dbus_message_unref (message);
00180       BUS_SET_OOM (error);
00181       return FALSE;
00182     }
00183 
00184   if (!bus_transaction_send_from_driver (transaction, connection, message))
00185     {
00186       dbus_message_unref (message);
00187       BUS_SET_OOM (error);
00188       return FALSE;
00189     }
00190   else
00191     {
00192       dbus_message_unref (message);
00193       return TRUE;
00194     }
00195 }
00196 
00197 static dbus_bool_t
00198 create_unique_client_name (BusRegistry *registry,
00199                            DBusString  *str)
00200 {
00201   /* We never want to use the same unique client name twice, because
00202    * we want to guarantee that if you send a message to a given unique
00203    * name, you always get the same application. So we use two numbers
00204    * for INT_MAX * INT_MAX combinations, should be pretty safe against
00205    * wraparound.
00206    */
00207   /* FIXME these should be in BusRegistry rather than static vars */
00208   static int next_major_number = 0;
00209   static int next_minor_number = 0;
00210   int len;
00211   
00212   len = _dbus_string_get_length (str);
00213   
00214   while (TRUE)
00215     {
00216       /* start out with 1-0, go to 1-1, 1-2, 1-3,
00217        * up to 1-MAXINT, then 2-0, 2-1, etc.
00218        */
00219       if (next_minor_number <= 0)
00220         {
00221           next_major_number += 1;
00222           next_minor_number = 0;
00223           if (next_major_number <= 0)
00224             _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
00225         }
00226 
00227       _dbus_assert (next_major_number > 0);
00228       _dbus_assert (next_minor_number >= 0);
00229 
00230       /* appname:MAJOR-MINOR */
00231       
00232       if (!_dbus_string_append (str, ":"))
00233         return FALSE;
00234       
00235       if (!_dbus_string_append_int (str, next_major_number))
00236         return FALSE;
00237 
00238       if (!_dbus_string_append (str, "-"))
00239         return FALSE;
00240       
00241       if (!_dbus_string_append_int (str, next_minor_number))
00242         return FALSE;
00243 
00244       next_minor_number += 1;
00245       
00246       /* Check if a client with the name exists */
00247       if (bus_registry_lookup (registry, str) == NULL)
00248         break;
00249 
00250       /* drop the number again, try the next one. */
00251       _dbus_string_set_length (str, len);
00252     }
00253 
00254   return TRUE;
00255 }
00256 
00257 static dbus_bool_t
00258 bus_driver_handle_hello (DBusConnection *connection,
00259                          BusTransaction *transaction,
00260                          DBusMessage    *message,
00261                          DBusError      *error)
00262 {
00263   DBusString unique_name;
00264   BusService *service;
00265   dbus_bool_t retval;
00266   BusRegistry *registry;
00267   BusConnections *connections;
00268 
00269   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00270 
00271   /* Note that when these limits are exceeded we don't disconnect the
00272    * connection; we just sort of leave it hanging there until it times
00273    * out or disconnects itself or is dropped due to the max number of
00274    * incomplete connections. It's even OK if the connection wants to
00275    * retry the hello message, we support that.
00276    */
00277   connections = bus_connection_get_connections (connection);
00278   if (!bus_connections_check_limits (connections, connection,
00279                                      error))
00280     {
00281       _DBUS_ASSERT_ERROR_IS_SET (error);
00282       return FALSE;
00283     }
00284   
00285   if (!_dbus_string_init (&unique_name))
00286     {
00287       BUS_SET_OOM (error);
00288       return FALSE;
00289     }
00290 
00291   retval = FALSE;
00292 
00293   registry = bus_connection_get_registry (connection);
00294   
00295   if (!create_unique_client_name (registry, &unique_name))
00296     {
00297       BUS_SET_OOM (error);
00298       goto out_0;
00299     }
00300 
00301   if (!bus_connection_complete (connection, &unique_name, error))
00302     {
00303       _DBUS_ASSERT_ERROR_IS_SET (error);
00304       goto out_0;
00305     }
00306   
00307   if (!dbus_message_set_sender (message,
00308                                 bus_connection_get_name (connection)))
00309     {
00310       BUS_SET_OOM (error);
00311       goto out_0;
00312     }
00313   
00314   if (!bus_driver_send_welcome_message (connection, message, transaction, error))
00315     goto out_0;
00316 
00317   /* Create the service */
00318   service = bus_registry_ensure (registry,
00319                                  &unique_name, connection, transaction, error);
00320   if (service == NULL)
00321     goto out_0;
00322   
00323   bus_service_set_prohibit_replacement (service, TRUE);
00324 
00325   retval = TRUE;
00326   
00327  out_0:
00328   _dbus_string_free (&unique_name);
00329   return retval;
00330 }
00331 
00332 static dbus_bool_t
00333 bus_driver_send_welcome_message (DBusConnection *connection,
00334                                  DBusMessage    *hello_message,
00335                                  BusTransaction *transaction,
00336                                  DBusError      *error)
00337 {
00338   DBusMessage *welcome;
00339   const char *name;
00340 
00341   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00342   
00343   name = bus_connection_get_name (connection);
00344   _dbus_assert (name != NULL);
00345   
00346   welcome = dbus_message_new_reply (hello_message);
00347   if (welcome == NULL)
00348     {
00349       BUS_SET_OOM (error);
00350       return FALSE;
00351     }
00352   
00353   if (!dbus_message_append_args (welcome,
00354                                  DBUS_TYPE_STRING, name,
00355                                  DBUS_TYPE_INVALID))
00356     {
00357       dbus_message_unref (welcome);
00358       BUS_SET_OOM (error);
00359       return FALSE;
00360     }
00361 
00362   if (!bus_transaction_send_from_driver (transaction, connection, welcome))
00363     {
00364       dbus_message_unref (welcome);
00365       BUS_SET_OOM (error);
00366       return FALSE;
00367     }
00368   else
00369     {
00370       dbus_message_unref (welcome);
00371       return TRUE;
00372     }
00373 }
00374 
00375 static dbus_bool_t
00376 bus_driver_handle_list_services (DBusConnection *connection,
00377                                  BusTransaction *transaction,
00378                                  DBusMessage    *message,
00379                                  DBusError      *error)
00380 {
00381   DBusMessage *reply;
00382   int len;
00383   char **services;
00384   BusRegistry *registry;
00385 
00386   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00387   
00388   registry = bus_connection_get_registry (connection);
00389   
00390   reply = dbus_message_new_reply (message);
00391   if (reply == NULL)
00392     {
00393       BUS_SET_OOM (error);
00394       return FALSE;
00395     }
00396 
00397   if (!bus_registry_list_services (registry, &services, &len))
00398     {
00399       dbus_message_unref (reply);
00400       BUS_SET_OOM (error);
00401       return FALSE;
00402     }
00403   
00404   if (!dbus_message_append_args (reply,
00405                                  DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, services, len,
00406                                  DBUS_TYPE_INVALID))
00407     {
00408       dbus_free_string_array (services);
00409       dbus_message_unref (reply);
00410       BUS_SET_OOM (error);
00411       return FALSE;
00412     }
00413 
00414   dbus_free_string_array (services);
00415   
00416   if (!bus_transaction_send_from_driver (transaction, connection, reply))
00417     {
00418       dbus_message_unref (reply);
00419       BUS_SET_OOM (error);
00420       return FALSE;
00421     }
00422   else
00423     {
00424       dbus_message_unref (reply);
00425       return TRUE;
00426     }
00427 }
00428 
00429 static dbus_bool_t
00430 bus_driver_handle_acquire_service (DBusConnection *connection,
00431                                    BusTransaction *transaction,
00432                                    DBusMessage    *message,
00433                                    DBusError      *error)
00434 {
00435   DBusMessage *reply;
00436   DBusString service_name;
00437   char *name;
00438   int service_reply;
00439   int flags;
00440   dbus_bool_t retval;
00441   BusRegistry *registry;
00442 
00443   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00444   
00445   registry = bus_connection_get_registry (connection);
00446   
00447   if (!dbus_message_get_args (message, error,
00448                               DBUS_TYPE_STRING, &name,
00449                               DBUS_TYPE_UINT32, &flags,
00450                               DBUS_TYPE_INVALID))
00451     return FALSE;
00452   
00453   _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags);
00454   
00455   retval = FALSE;
00456   reply = NULL;
00457 
00458   _dbus_string_init_const (&service_name, name);
00459 
00460   if (!bus_registry_acquire_service (registry, connection,
00461                                      &service_name, flags,
00462                                      &service_reply, transaction,
00463                                      error))
00464     goto out;
00465   
00466   reply = dbus_message_new_reply (message);
00467   if (reply == NULL)
00468     {
00469       BUS_SET_OOM (error);
00470       goto out;
00471     }
00472 
00473   if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, DBUS_TYPE_INVALID))
00474     {
00475       BUS_SET_OOM (error);
00476       goto out;
00477     }
00478 
00479   if (!bus_transaction_send_from_driver (transaction, connection, reply))
00480     {
00481       BUS_SET_OOM (error);
00482       goto out;
00483     }
00484 
00485   retval = TRUE;
00486   
00487  out:
00488   dbus_free (name);
00489   if (reply)
00490     dbus_message_unref (reply);
00491   return retval;
00492 } 
00493 
00494 static dbus_bool_t
00495 bus_driver_handle_service_exists (DBusConnection *connection,
00496                                   BusTransaction *transaction,
00497                                   DBusMessage    *message,
00498                                   DBusError      *error)
00499 {
00500   DBusMessage *reply;
00501   DBusString service_name;
00502   BusService *service;
00503   char *name;
00504   dbus_bool_t retval;
00505   BusRegistry *registry;
00506 
00507   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00508   
00509   registry = bus_connection_get_registry (connection);
00510   
00511   if (!dbus_message_get_args (message, error,
00512                               DBUS_TYPE_STRING, &name,
00513                               DBUS_TYPE_INVALID))
00514     return FALSE;
00515 
00516   retval = FALSE;
00517   
00518   _dbus_string_init_const (&service_name, name);
00519   service = bus_registry_lookup (registry, &service_name);
00520  
00521   reply = dbus_message_new_reply (message);
00522   if (reply == NULL)
00523     {
00524       BUS_SET_OOM (error);
00525       goto out;
00526     }
00527 
00528   if (!dbus_message_append_args (reply,
00529                                  DBUS_TYPE_UINT32, service != NULL,
00530                                  0))
00531     {
00532       BUS_SET_OOM (error);
00533       goto out;
00534     }
00535 
00536   if (!bus_transaction_send_from_driver (transaction, connection, reply))
00537     {
00538       BUS_SET_OOM (error);
00539       goto out;
00540     }
00541 
00542   retval = TRUE;
00543   
00544  out:
00545   if (reply)
00546     dbus_message_unref (reply);
00547   dbus_free (name);
00548 
00549   return retval;
00550 }
00551 
00552 static dbus_bool_t
00553 bus_driver_handle_activate_service (DBusConnection *connection,
00554                                     BusTransaction *transaction,
00555                                     DBusMessage    *message,
00556                                     DBusError      *error)
00557 {
00558   dbus_uint32_t flags;
00559   char *name;
00560   dbus_bool_t retval;
00561   BusActivation *activation;
00562 
00563   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00564   
00565   activation = bus_connection_get_activation (connection);
00566   
00567   if (!dbus_message_get_args (message, error,
00568                               DBUS_TYPE_STRING, &name,
00569                               DBUS_TYPE_UINT32, &flags,
00570                               DBUS_TYPE_INVALID))
00571     {
00572       _DBUS_ASSERT_ERROR_IS_SET (error);
00573       _dbus_verbose ("No memory to get arguments to ActivateService\n");
00574       return FALSE;
00575     }
00576 
00577   retval = FALSE;
00578 
00579   if (!bus_activation_activate_service (activation, connection, transaction,
00580                                         message, name, error))
00581     {
00582       _DBUS_ASSERT_ERROR_IS_SET (error);
00583       _dbus_verbose ("bus_activation_activate_service() failed\n");
00584       goto out;
00585     }
00586 
00587   retval = TRUE;
00588   
00589  out:
00590   dbus_free (name);
00591   return retval;
00592 }
00593 
00594 /* For speed it might be useful to sort this in order of
00595  * frequency of use (but doesn't matter with only a few items
00596  * anyhow)
00597  */
00598 struct
00599 {
00600   const char *name;
00601   dbus_bool_t (* handler) (DBusConnection *connection,
00602                            BusTransaction *transaction,
00603                            DBusMessage    *message,
00604                            DBusError      *error);
00605 } message_handlers[] = {
00606   { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
00607   { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
00608   { DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
00609   { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
00610   { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
00611 };
00612 
00613 dbus_bool_t
00614 bus_driver_handle_message (DBusConnection *connection,
00615                            BusTransaction *transaction,
00616                            DBusMessage    *message,
00617                            DBusError      *error)
00618 {
00619   const char *name, *sender;
00620   int i;
00621 
00622   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00623   
00624   _dbus_verbose ("Driver got a message: %s\n",
00625                  dbus_message_get_name (message));
00626   
00627   name = dbus_message_get_name (message);
00628   sender = dbus_message_get_sender (message);
00629 
00630   /* security checks should have kept this from getting here */
00631   _dbus_assert (sender != NULL || strcmp (name, DBUS_MESSAGE_HELLO) == 0);
00632 
00633   if (dbus_message_get_reply_serial (message) == 0)
00634     {
00635       _dbus_verbose ("Client sent a reply to the bus driver, ignoring it\n");
00636       return TRUE;
00637     }
00638   
00639   i = 0;
00640   while (i < _DBUS_N_ELEMENTS (message_handlers))
00641     {
00642       if (strcmp (message_handlers[i].name, name) == 0)
00643         {
00644           _dbus_verbose ("Running driver handler for %s\n", name);
00645           if ((* message_handlers[i].handler) (connection, transaction, message, error))
00646             {
00647               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00648               _dbus_verbose ("Driver handler succeeded\n");
00649               return TRUE;
00650             }
00651           else
00652             {
00653               _DBUS_ASSERT_ERROR_IS_SET (error);
00654               _dbus_verbose ("Driver handler returned failure\n");
00655               return FALSE;
00656             }
00657         }
00658       
00659       ++i;
00660     }
00661 
00662   _dbus_verbose ("No driver handler for %s\n", name);
00663 
00664   dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
00665                   "%s does not understand message %s",
00666                   DBUS_SERVICE_DBUS, name);
00667   
00668   return FALSE;
00669 }
00670 
00671 void
00672 bus_driver_remove_connection (DBusConnection *connection)
00673 {
00674   /* FIXME Does nothing for now, should unregister the connection
00675    * with the bus driver.
00676    */
00677 }

Generated on Wed Oct 22 14:05:06 2003 for D-BUS by doxygen1.3-rc3