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