driver.c revision d5ad082fecbbd803fd89b3574ac137b3fa964bc7
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 <dbus/dbus-string.h> 29#include <dbus/dbus-internals.h> 30#include <string.h> 31 32static void bus_driver_send_welcome_message (DBusConnection *connection, 33 DBusMessage *hello_message); 34 35static void 36bus_driver_send_service_deleted (DBusConnection *connection, const char *name) 37{ 38 DBusMessage *message; 39 40 _dbus_verbose ("sending service deleted: %s\n", name); 41 42 _DBUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, 43 DBUS_MESSAGE_SERVICE_DELETED)); 44 45 _DBUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); 46 47 _DBUS_HANDLE_OOM (dbus_message_append_fields (message, 48 DBUS_TYPE_STRING, name, 49 0)); 50 bus_dispatch_broadcast_message (message); 51 dbus_message_unref (message); 52} 53 54static void 55bus_driver_send_service_created (DBusConnection *connection, const char *name) 56{ 57 DBusMessage *message; 58 59 _DBUS_HANDLE_OOM (message = dbus_message_new (DBUS_SERVICE_BROADCAST, 60 DBUS_MESSAGE_SERVICE_CREATED)); 61 62 _DBUS_HANDLE_OOM (dbus_message_set_sender (message, DBUS_SERVICE_DBUS)); 63 64 _DBUS_HANDLE_OOM (dbus_message_append_fields (message, 65 DBUS_TYPE_STRING, name, 66 0)); 67 bus_dispatch_broadcast_message (message); 68 dbus_message_unref (message); 69} 70 71static dbus_bool_t 72create_unique_client_name (const char *name, 73 DBusString *str) 74{ 75 /* We never want to use the same unique client name twice, because 76 * we want to guarantee that if you send a message to a given unique 77 * name, you always get the same application. So we use two numbers 78 * for INT_MAX * INT_MAX combinations, should be pretty safe against 79 * wraparound. 80 */ 81 static int next_major_number = 0; 82 static int next_minor_number = 0; 83 int len; 84 85 if (!_dbus_string_append (str, name)) 86 return FALSE; 87 88 len = _dbus_string_get_length (str); 89 90 while (TRUE) 91 { 92 /* start out with 1-0, go to 1-1, 1-2, 1-3, 93 * up to 1-MAXINT, then 2-0, 2-1, etc. 94 */ 95 if (next_minor_number <= 0) 96 { 97 next_major_number += 1; 98 next_minor_number = 0; 99 if (next_major_number <= 0) 100 _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added"); 101 } 102 103 _dbus_assert (next_major_number > 0); 104 _dbus_assert (next_minor_number >= 0); 105 106 /* appname:MAJOR-MINOR */ 107 108 if (!_dbus_string_append (str, ":")) 109 return FALSE; 110 111 if (!_dbus_string_append_int (str, next_major_number)) 112 return FALSE; 113 114 if (!_dbus_string_append (str, "-")) 115 return FALSE; 116 117 if (!_dbus_string_append_int (str, next_minor_number)) 118 return FALSE; 119 120 next_minor_number += 1; 121 122 /* Check if a client with the name exists */ 123 if (bus_service_lookup (str, FALSE) == NULL) 124 break; 125 126 /* drop the number again, try the next one. */ 127 _dbus_string_set_length (str, len); 128 } 129 130 return TRUE; 131} 132 133static void 134bus_driver_handle_hello (DBusConnection *connection, 135 DBusMessage *message) 136{ 137 DBusResultCode result; 138 char *name; 139 DBusString unique_name; 140 BusService *service; 141 142 _DBUS_HANDLE_OOM ((result = dbus_message_get_fields (message, 143 DBUS_TYPE_STRING, &name, 144 0)) != DBUS_RESULT_NO_MEMORY); 145 146 if (result != DBUS_RESULT_SUCCESS) 147 { 148 dbus_free (name); 149 dbus_connection_disconnect (connection); 150 } 151 152 _DBUS_HANDLE_OOM (_dbus_string_init (&unique_name, _DBUS_INT_MAX)); 153 154 _DBUS_HANDLE_OOM (create_unique_client_name (name, &unique_name)); 155 156 dbus_free (name); 157 158 /* Create the service */ 159 _DBUS_HANDLE_OOM (service = bus_service_lookup (&unique_name, TRUE)); 160 161 /* Add the connection as the owner */ 162 _DBUS_HANDLE_OOM (bus_service_add_owner (service, connection)); 163 _DBUS_HANDLE_OOM (bus_connection_set_name (connection, &unique_name)); 164 165 _DBUS_HANDLE_OOM (dbus_message_set_sender (message, 166 bus_connection_get_name (connection))); 167 168 _dbus_string_free (&unique_name); 169 170 _DBUS_HANDLE_OOM (bus_driver_send_welcome_message (connection, message)); 171 172 /* Broadcast a service created message */ 173 bus_driver_send_service_created (connection, bus_service_get_name (service)); 174} 175 176static void 177bus_driver_send_welcome_message (DBusConnection *connection, 178 DBusMessage *hello_message) 179{ 180 DBusMessage *welcome; 181 const char *name; 182 183 name = bus_connection_get_name (connection); 184 _dbus_assert (name != NULL); 185 186 _DBUS_HANDLE_OOM (welcome = dbus_message_new_reply (DBUS_MESSAGE_WELCOME, 187 hello_message)); 188 189 _DBUS_HANDLE_OOM (dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS)); 190 191 _DBUS_HANDLE_OOM (dbus_message_append_fields (welcome, 192 DBUS_TYPE_STRING, name, 193 NULL)); 194 195 _DBUS_HANDLE_OOM (dbus_connection_send_message (connection, welcome, NULL, NULL)); 196 197 dbus_message_unref (welcome); 198} 199 200static void 201bus_driver_handle_list_services (DBusConnection *connection, 202 DBusMessage *message) 203{ 204 DBusMessage *reply; 205 int len, i; 206 char **services; 207 208 _DBUS_HANDLE_OOM (reply = dbus_message_new_reply (DBUS_MESSAGE_SERVICES, message)); 209 210 _DBUS_HANDLE_OOM (services = bus_services_list (&len)); 211 212 _DBUS_HANDLE_OOM (dbus_message_append_fields (reply, 213 DBUS_TYPE_STRING_ARRAY, services, len, 214 0)); 215 216 _DBUS_HANDLE_OOM (dbus_connection_send_message (connection, reply, NULL, NULL)); 217 218 dbus_message_unref (reply); 219 220 if (services != NULL) 221 { 222 for (i = 0; i < len; i++) 223 dbus_free (services[i]); 224 dbus_free (services); 225 } 226} 227 228void 229bus_driver_remove_connection (DBusConnection *connection) 230{ 231 BusService *service; 232 DBusString service_name; 233 const char *name; 234 235 name = bus_connection_get_name (connection); 236 237 if (name == NULL) 238 return; 239 240 _dbus_string_init_const (&service_name, name); 241 242 service = bus_service_lookup (&service_name, FALSE); 243 244 bus_driver_send_service_deleted (connection, name); 245 246 if (service) 247 bus_service_free (service); 248} 249 250void 251bus_driver_handle_message (DBusConnection *connection, 252 DBusMessage *message) 253{ 254 const char *name, *sender; 255 256 _dbus_verbose ("Driver got a message: %s\n", 257 dbus_message_get_name (message)); 258 259 name = dbus_message_get_name (message); 260 sender = dbus_message_get_sender (message); 261 262 if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0)) 263 { 264 _dbus_verbose ("Trying to send a message without being registered. Disconnecting.\n"); 265 dbus_connection_disconnect (connection); 266 return; 267 } 268 269 /* Now check names. */ 270 if (strcmp (name, DBUS_MESSAGE_HELLO) == 0) 271 bus_driver_handle_hello (connection, message); 272 else if (strcmp (name, DBUS_MESSAGE_LIST_SERVICES) == 0) 273 bus_driver_handle_list_services (connection, message); 274} 275