driver.c revision aa4b4ef5955606659557a40a2220090ee9c108d4
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 "connection.h" 25#include "driver.h" 26#include "dispatch.h" 27#include "services.h" 28#include "utils.h" 29#include <dbus/dbus-string.h> 30#include <dbus/dbus-internals.h> 31#include <string.h> 32 33static void bus_driver_send_welcome_message (DBusConnection *connection, 34 DBusMessage *hello_message); 35 36void 37bus_driver_send_service_deleted (const char *service_name) 38{ 39 DBusMessage *message; 40 41 _dbus_verbose ("sending service deleted: %s\n", service_name); 42 43 BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, 44 DBUS_MESSAGE_SERVICE_DELETED)); 45 46 BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); 47 48 BUS_HANDLE_OOM (dbus_message_append_args (message, 49 DBUS_TYPE_STRING, service_name, 50 0)); 51 bus_dispatch_broadcast_message (message); 52 dbus_message_unref (message); 53} 54 55static void 56bus_driver_send_service_created (const char *service_name) 57{ 58 DBusMessage *message; 59 60 BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, 61 DBUS_MESSAGE_SERVICE_CREATED)); 62 63 BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); 64 65 BUS_HANDLE_OOM (dbus_message_append_args (message, 66 DBUS_TYPE_STRING, service_name, 67 0)); 68 bus_dispatch_broadcast_message (message); 69 dbus_message_unref (message); 70} 71 72void 73bus_driver_send_service_lost (DBusConnection *connection, 74 const char *service_name) 75{ 76 DBusMessage *message; 77 78 BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, 79 DBUS_MESSAGE_SERVICE_LOST)); 80 81 BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); 82 BUS_HANDLE_OOM (dbus_message_append_args (message, 83 DBUS_TYPE_STRING, service_name, 84 0)); 85 BUS_HANDLE_OOM (dbus_connection_send_message (connection, message, NULL, NULL)); 86 87 dbus_message_unref (message); 88} 89 90void 91bus_driver_send_service_acquired (DBusConnection *connection, 92 const char *service_name) 93{ 94 DBusMessage *message; 95 96 BUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, 97 DBUS_MESSAGE_SERVICE_ACQUIRED)); 98 99 BUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); 100 BUS_HANDLE_OOM (dbus_message_append_args (message, 101 DBUS_TYPE_STRING, service_name, 102 0)); 103 BUS_HANDLE_OOM (dbus_connection_send_message (connection, message, NULL, NULL)); 104 105 dbus_message_unref (message); 106} 107 108static dbus_bool_t 109create_unique_client_name (DBusString *str) 110{ 111 /* We never want to use the same unique client name twice, because 112 * we want to guarantee that if you send a message to a given unique 113 * name, you always get the same application. So we use two numbers 114 * for INT_MAX * INT_MAX combinations, should be pretty safe against 115 * wraparound. 116 */ 117 static int next_major_number = 0; 118 static int next_minor_number = 0; 119 int len; 120 121 len = _dbus_string_get_length (str); 122 123 while (TRUE) 124 { 125 /* start out with 1-0, go to 1-1, 1-2, 1-3, 126 * up to 1-MAXINT, then 2-0, 2-1, etc. 127 */ 128 if (next_minor_number <= 0) 129 { 130 next_major_number += 1; 131 next_minor_number = 0; 132 if (next_major_number <= 0) 133 _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added"); 134 } 135 136 _dbus_assert (next_major_number > 0); 137 _dbus_assert (next_minor_number >= 0); 138 139 /* appname:MAJOR-MINOR */ 140 141 if (!_dbus_string_append (str, ":")) 142 return FALSE; 143 144 if (!_dbus_string_append_int (str, next_major_number)) 145 return FALSE; 146 147 if (!_dbus_string_append (str, "-")) 148 return FALSE; 149 150 if (!_dbus_string_append_int (str, next_minor_number)) 151 return FALSE; 152 153 next_minor_number += 1; 154 155 /* Check if a client with the name exists */ 156 if (bus_service_lookup (str, FALSE) == NULL) 157 break; 158 159 /* drop the number again, try the next one. */ 160 _dbus_string_set_length (str, len); 161 } 162 163 return TRUE; 164} 165 166static void 167bus_driver_handle_hello (DBusConnection *connection, 168 DBusMessage *message) 169{ 170 DBusString unique_name; 171 BusService *service; 172 173 BUS_HANDLE_OOM (_dbus_string_init (&unique_name, _DBUS_INT_MAX)); 174 BUS_HANDLE_OOM (create_unique_client_name (&unique_name)); 175 176 /* Create the service */ 177 BUS_HANDLE_OOM (service = bus_service_lookup (&unique_name, TRUE)); 178 bus_service_set_prohibit_replacement (service, TRUE); 179 180 /* Add the connection as the owner */ 181 BUS_HANDLE_OOM (bus_service_add_owner (service, connection)); 182 BUS_HANDLE_OOM (bus_connection_set_name (connection, &unique_name)); 183 184 BUS_HANDLE_OOM (dbus_message_set_sender (message, 185 bus_connection_get_name (connection))); 186 187 _dbus_string_free (&unique_name); 188 189 BUS_HANDLE_OOM (bus_driver_send_welcome_message (connection, message)); 190 191 /* Broadcast a service created message */ 192 bus_driver_send_service_created (bus_service_get_name (service)); 193} 194 195static void 196bus_driver_send_welcome_message (DBusConnection *connection, 197 DBusMessage *hello_message) 198{ 199 DBusMessage *welcome; 200 const char *name; 201 202 name = bus_connection_get_name (connection); 203 _dbus_assert (name != NULL); 204 205 BUS_HANDLE_OOM (welcome = dbus_message_new_reply (hello_message)); 206 207 BUS_HANDLE_OOM (dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS)); 208 209 BUS_HANDLE_OOM (dbus_message_append_args (welcome, 210 DBUS_TYPE_STRING, name, 211 NULL)); 212 213 BUS_HANDLE_OOM (dbus_connection_send_message (connection, welcome, NULL, NULL)); 214 215 dbus_message_unref (welcome); 216} 217 218static void 219bus_driver_handle_list_services (DBusConnection *connection, 220 DBusMessage *message) 221{ 222 DBusMessage *reply; 223 int len, i; 224 char **services; 225 226 BUS_HANDLE_OOM (reply = dbus_message_new_reply (message)); 227 228 BUS_HANDLE_OOM (services = bus_services_list (&len)); 229 230 BUS_HANDLE_OOM (dbus_message_append_args (reply, 231 DBUS_TYPE_STRING_ARRAY, services, len, 232 0)); 233 234 BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL)); 235 236 dbus_message_unref (reply); 237 238 if (services != NULL) 239 { 240 for (i = 0; i < len; i++) 241 dbus_free (services[i]); 242 dbus_free (services); 243 } 244} 245 246static void 247bus_driver_handle_acquire_service (DBusConnection *connection, 248 DBusMessage *message) 249{ 250 DBusMessage *reply; 251 DBusResultCode result; 252 DBusString service_name; 253 BusService *service; 254 char *name; 255 int service_reply; 256 int flags; 257 258 BUS_HANDLE_OOM ((result = dbus_message_get_args (message, 259 DBUS_TYPE_STRING, &name, 260 DBUS_TYPE_UINT32, &flags, 261 0)) != DBUS_RESULT_NO_MEMORY); 262 263 if (result != DBUS_RESULT_SUCCESS) 264 { 265 dbus_free (name); 266 dbus_connection_disconnect (connection); 267 return; 268 } 269 270 _dbus_verbose ("Trying to own service %s with flags %d\n", name, flags); 271 272 _dbus_string_init_const (&service_name, name); 273 service = bus_service_lookup (&service_name, TRUE); 274 275 BUS_HANDLE_OOM ((reply = dbus_message_new_reply (message))); 276 277 /* 278 * Check if the service already has an owner 279 */ 280 if (bus_service_get_primary_owner (service) != NULL) 281 { 282 if (bus_service_has_owner (service, connection)) 283 service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER; 284 else if (!(flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING)) 285 service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS; 286 else 287 { 288 if (bus_service_get_prohibit_replacement (service)) 289 { 290 291 /* Queue the connection */ 292 BUS_HANDLE_OOM (bus_service_add_owner (service, connection)); 293 294 service_reply = DBUS_SERVICE_REPLY_IN_QUEUE; 295 } 296 else 297 { 298 DBusConnection *owner; 299 300 /* We can replace the primary owner */ 301 owner = bus_service_get_primary_owner (service); 302 303 /* We enqueue the new owner and remove the first one because 304 * that will cause ServiceAcquired and ServiceLost messages to 305 * be sent. 306 */ 307 BUS_HANDLE_OOM (bus_service_add_owner (service, connection)); 308 bus_service_remove_owner (service, owner); 309 _dbus_assert (connection == bus_service_get_primary_owner (service)); 310 service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER; 311 } 312 } 313 } 314 else 315 { 316 bus_service_set_prohibit_replacement (service, 317 (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT)); 318 319 /* Broadcast service created message */ 320 bus_driver_send_service_created (bus_service_get_name (service)); 321 322 BUS_HANDLE_OOM (bus_service_add_owner (service, connection)); 323 324 service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER; 325 } 326 327 BUS_HANDLE_OOM (dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0)); 328 329 /* Send service reply */ 330 BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL)); 331 dbus_free (name); 332 dbus_message_unref (reply); 333} 334 335static void 336bus_driver_handle_service_exists (DBusConnection *connection, 337 DBusMessage *message) 338{ 339 DBusMessage *reply; 340 DBusResultCode result; 341 DBusString service_name; 342 BusService *service; 343 char *name; 344 345 BUS_HANDLE_OOM ((result = dbus_message_get_args (message, 346 DBUS_TYPE_STRING, &name, 347 0)) != DBUS_RESULT_NO_MEMORY); 348 if (result != DBUS_RESULT_SUCCESS) 349 { 350 dbus_free (name); 351 dbus_connection_disconnect (connection); 352 return; 353 } 354 355 _dbus_string_init_const (&service_name, name); 356 service = bus_service_lookup (&service_name, FALSE); 357 358 BUS_HANDLE_OOM ((reply = dbus_message_new_reply (message))); 359 BUS_HANDLE_OOM (dbus_message_set_sender (reply, DBUS_SERVICE_DBUS)); 360 361 BUS_HANDLE_OOM (dbus_message_append_args (reply, 362 DBUS_TYPE_UINT32, service != NULL, 363 0)); 364 BUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL)); 365 dbus_message_unref (reply); 366 dbus_free (name); 367} 368 369void 370bus_driver_handle_message (DBusConnection *connection, 371 DBusMessage *message) 372{ 373 const char *name, *sender; 374 375 _dbus_verbose ("Driver got a message: %s\n", 376 dbus_message_get_name (message)); 377 378 name = dbus_message_get_name (message); 379 sender = dbus_message_get_sender (message); 380 381 if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0)) 382 { 383 _dbus_verbose ("Trying to send a message without being registered. Disconnecting.\n"); 384 dbus_connection_disconnect (connection); 385 return; 386 } 387 388 /* Now check names. */ 389 if (strcmp (name, DBUS_MESSAGE_HELLO) == 0) 390 bus_driver_handle_hello (connection, message); 391 else if (strcmp (name, DBUS_MESSAGE_LIST_SERVICES) == 0) 392 bus_driver_handle_list_services (connection, message); 393 else if (strcmp (name, DBUS_MESSAGE_ACQUIRE_SERVICE) == 0) 394 bus_driver_handle_acquire_service (connection, message); 395 else if (strcmp (name, DBUS_MESSAGE_SERVICE_EXISTS) == 0) 396 bus_driver_handle_service_exists (connection, message); 397 398} 399 400void 401bus_driver_remove_connection (DBusConnection *connection) 402{ 403 /* Does nothing for now */ 404} 405