2003-02-16 Anders Carlsson <andersca@codefactory.se>
[platform/upstream/dbus.git] / bus / dispatch.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dispatch.c  Message dispatcher
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 "dispatch.h"
25 #include "connection.h"
26 #include "driver.h"
27 #include "utils.h"
28 #include <dbus/dbus-internals.h>
29 #include <string.h>
30
31 static int message_handler_slot;
32
33 static void
34 send_one_message (DBusConnection *connection, void *data)
35 {
36   BUS_HANDLE_OOM (dbus_connection_send_message (connection, data, NULL, NULL));
37 }
38
39 void
40 bus_dispatch_broadcast_message (DBusMessage *message)
41 {
42   _dbus_assert (dbus_message_get_sender (message) != NULL);
43   
44   bus_connection_foreach (send_one_message, message);
45   
46 }
47
48 static DBusHandlerResult
49 bus_dispatch_message_handler (DBusMessageHandler *handler,
50                               DBusConnection     *connection,
51                               DBusMessage        *message,
52                               void               *user_data)
53 {
54   const char *sender, *service_name, *message_name;
55   
56   /* Assign a sender to the message */
57   sender = bus_connection_get_name (connection);
58   BUS_HANDLE_OOM (dbus_message_set_sender (message, sender));
59
60   service_name = dbus_message_get_service (message);
61   message_name = dbus_message_get_name (message);
62   
63   /* TODO: Crashes if service_name == NULL */
64   
65   /* See if the message is to the driver */
66   if (message_name && strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0)
67     {
68       bus_connection_disconnect (connection);
69     }
70   else if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0)
71     {
72       bus_driver_handle_message (connection, message);
73     }
74   else if (sender == NULL)
75     {
76       _dbus_verbose ("Received message from non-registered client. Disconnecting.\n");
77       dbus_connection_disconnect (connection);
78     }
79   else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0)
80     {
81       bus_dispatch_broadcast_message (message);
82     }
83   else  
84     {
85       DBusString service_string;
86       BusService *service;
87
88       _dbus_string_init_const (&service_string, service_name);
89       service = bus_service_lookup (&service_string, FALSE);
90
91       if (!service)
92         {
93           DBusMessage *error_reply;
94           DBusString error_message;
95           const char *error_str;
96           
97           /* Trying to send a message to a non-existant service,
98              bounce back an error message. */
99           
100           BUS_HANDLE_OOM (_dbus_string_init (&error_message, _DBUS_INT_MAX));
101
102           BUS_HANDLE_OOM (_dbus_string_append (&error_message, "Service \""));
103           BUS_HANDLE_OOM (_dbus_string_append (&error_message, service_name));
104           BUS_HANDLE_OOM (_dbus_string_append (&error_message, "does not exist"));        
105
106           _dbus_string_get_const_data (&error_message, &error_str);
107           BUS_HANDLE_OOM (error_reply = dbus_message_new_error_reply (message, DBUS_ERROR_SERVICE_DOES_NOT_EXIST,
108                                                                       error_str));
109           _dbus_string_free (&error_message);
110
111           /* Dispatch the message */
112           BUS_HANDLE_OOM (dbus_connection_send_message (connection, error_reply, NULL, NULL));
113           dbus_message_unref (error_reply);
114         }
115       else
116         {
117           _dbus_assert (bus_service_get_primary_owner (service) != NULL);
118       
119           /* Dispatch the message */
120           BUS_HANDLE_OOM (dbus_connection_send_message (bus_service_get_primary_owner (service),
121                                                         message, NULL, NULL));
122         }
123     }
124
125   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
126 }
127
128 dbus_bool_t
129 bus_dispatch_add_connection (DBusConnection *connection)
130 {
131   DBusMessageHandler *handler;
132   
133   message_handler_slot = dbus_connection_allocate_data_slot ();
134
135   if (message_handler_slot < 0)
136     return FALSE;
137
138   handler = dbus_message_handler_new (bus_dispatch_message_handler, NULL, NULL);  
139
140   if (!dbus_connection_add_filter (connection, handler))
141     {
142       dbus_message_handler_unref (handler);
143
144       return FALSE;
145     }
146
147   if (!dbus_connection_set_data (connection,
148                                  message_handler_slot,
149                                  handler,
150                                  (DBusFreeFunction)dbus_message_handler_unref))
151     {
152       dbus_connection_remove_filter (connection, handler);
153       dbus_message_handler_unref (handler);
154
155       return FALSE;
156     }
157
158   return TRUE;
159 }
160
161 void
162 bus_dispatch_remove_connection (DBusConnection *connection)
163 {
164   /* Here we tell the bus driver that we want to get off. */
165   bus_driver_remove_connection (connection);
166
167   dbus_connection_set_data (connection,
168                             message_handler_slot,
169                             NULL, NULL);
170 }
171